天天看點

Internal error during IncrBuildImage 問題的解決辦法 - J_July

Internal error during IncrBuildImage 問題的解決辦法

今天使用VS2008寫了一個基于MFC的對話框的程式,在編譯的時候出現了“LINK100:Internal error during IncrBuildImage“的錯誤,到網上搜了一下

找到錯誤的解決辦法:

 一、下微軟的更新檔:KB948127更新檔來解決,http://code.msdn.microsoft.com/KB948127。貌似安裝了也不起作用

    二、如果下載下傳的更新檔沒安裝成功或下載下傳失敗,可以用下面的方法手工來改工程設定 項目(Project)->屬性(Property)->連結器(Linker)->正常(General) 下面的“啟用增量連結(Enable Incremental Linking)”,将“是(/INCREMENTAL)”改為“否(/INCREMENTAL:NO)”。不過這又引入了另外一個警 告:FormatCom.obj : warning LNK4075: 忽略“/EDITANDCONTINUE”(由于“/INCREMENTAL:NO”規範)

    選擇項目,屬性(Property pages)->配置屬性(Configuration Properties) ->C/C++,修改“調試資訊格式(Debug Information Format)”為“程式資料庫(Program Database(/Zi))”即可。

網上有大牛寫的測試,需找原因,這裡引用一下  網址:http://blog.sina.com.cn/s/blog_7e01272201010k6d.html

看到這我又迷茫了,不斷咒罵vs複雜的同時我搜尋了增量連結這個東西,得到了如下的解釋:

好的,文接上回,本文我就來講講微軟link.exe連接配接器的Incremental Liking這個特性。當然這個其實不是微軟linker獨有的特性,很多連結器都有這個特性,這個特性實際上是為了提高連結速度的。

   想象一下這個場景,我寫了兩個函數foo()和bar(),其中foo()在0x400100處而bar()緊接着儲存在0x400200處。現在我将 foo()改寫了一下,添加了一些perfect的功能,然後編譯了新的代碼。不過現在的麻煩是foo()不可避免的變大了,他現在需要200h位元組來保 存了。那麼連結器該怎麼辦?

   一般的思考是——重新洗牌,将現有的編譯好的exe删除了,然後重新布局所有的函數,也即是說bar()函數向後挪動0x100h位元組的位置,給 foo()騰出空間來。然後之後所有的函數都需要重新定位……對于大型軟體來說這個處理時間開銷是痛苦的,但作為程式員我們卻不能避免需要不斷的調試改代 碼,不斷地重複這個耗時的工作。

  不過我們現在并不需要給客戶最終的發行代碼,我們隻是想要盡快地将程式的bug改掉然後去休息而已!于是,Incremental Linking出現了!它的原理如下:

Internal error during IncrBuildImage 問題的解決辦法 - J_July

  現在連接配接器不會将所有函數緊挨着放在一塊兒了,他們會在函數之間加上padding,這個時候函數要想添幾句指令就有餘地了。隻要我們的改動不大,沒有超過padding的範圍連接配接器就不需要重新洗牌,這大大提高了連結的速度。

   先别高興,加入我們的改動很大,以至于超過padding能夠搞定的範圍怎麼辦?如上圖,我們還會在整個section末尾設定一個較大的 padding(當然具體在哪裡要看實作,比如我這圖是從GCC那裡搞得,說的就是ld.exe的行為方式),這時候就可以将這個函數搬到這裡來了。但有 個毀滅性的問題——所有調用我這個函數的函數都必須重定位他們的call指令啊!

  為了解決這個問題,我們引入了一個ILT表(Incremental Linking Table),這個表是放在.text區域中的(我在IDA中觀察得知)。它的原理是什麼呢?我們來看:

;之前我們都是直接調用函數
call foo

;現在我們來點小把戲
call foo_stub

foo_stub:
jmp foo      

複制代碼

  我們現在不直接調用函數,而是call到一個包含jmp指令的地方,然後由這個指令将我們的程度帶往foo()函數的實作去。現在如果我們将 foo()的實作改動過大後,linker直接将foo()移動了,然後隻需要修改這個jmp指令就行了。可以看到,這種實作方式開銷是O(1)。然後當 很多個函數都用這種方式時,就形成了一個有jmp指令構成的表——這就是ILT表啦。

  有興趣的童鞋可以做下實驗,在VS2010編譯一次代碼,然後用IDA或者W32Dasm之類的軟體可以看到兩個函數之間間隔了不少距離,而這些間隔就是我們所謂padding。padding被填充以0xCCh的資料。熟悉win32彙編的朋友這時候該笑而不語了,是的,這個值就是指令INT 3。在WIndows下,執行這個指令會引發一個異常,然後程式會被終止或是回到調試器去,這當然是出于安全性考慮的。這之後如果你在前一個函數加幾句話,編譯後可以看到兩個函數位置不變,但函數間的padding變小了。

發表于

2015-07-30 22:07 

J_July 

閱讀(989) 

評論(0) 

編輯 

收藏 

舉報