VC的IDE在編譯鏈接時做了些什麼

在找nMake和makefile資料時瀏覽到的,一開始沒讀懂,先收藏了再說,留待以後慢慢消化。

做人要HD,原文地址:http://blog.csdn.net/aganno2/archive/2006/12/14/1443097.aspx

雖然原文中做了mouseselect=reture false,呵呵

                   
<script type="text/javascript"></script>

-------------

1.VC的IDE在編譯鏈接做了些什麼

用慣了VC的IDE下習慣性的點擊“compile”和“build”的可能不知道在你按下這些按鈕時IDE在背後到底做了寫什麼,對於熟悉命令行下進行編譯鏈接的人對cl.exe、link.exe、rc.exe這些編譯鏈接的工具不是陌生的,在這裏我並不想討論這些工具怎樣進行編譯的以及那些名目繁多的選項參數,而是從“亞微觀”上揭開在你點擊那些按鈕之後,IDE在背後乾的事情,肯定有初學者像我一樣想了解,當然那些unix/linux下的程序員以及會寫makefile來組織編譯鏈接進程的Profession的程序員就不用看下去了。

 

正在裝載數據……

 

 

 

2.vcspawn的選項和參數

vcspawn,突然說到這個可能很多不大熟,其實在你點擊那些按鈕的時候,並不是由IDE自己直接去調用cl.exe、link.exe、rc.exe這些工具的,而是通過vcspawn.exe這個工具進行中轉的,簡單說IDE把參數傳遞給vcspawn,然後由vcspawn來建立進程去執行這些編譯鏈接的命令,然後把編譯鏈接過程中的信息輸出到IDE的最下面的輸出窗口的,在這裏vcspawn的輸出被重定向到那個窗口了(一般通過管道),而由vcspawn新建的進程由於繼承了父進程的輸出,因此也會把重定向到IDE的輸出窗口。

下面是個典型的IDE向vcspawn傳遞的參數:(M$對這些參數好像一點文檔都沒有,這些是通過調式手段截獲的)

VCSPAWN.EXE -e 1380 -m ~vcecho!Compiling resources.../n
rc.exe /l 0x804 "/foRelease/SSDowner.res" /d "NDEBUG" "D:/Microsoft Visual Studio/MyProjects/test/test.rc"/n
~vcecho!Compiling.../n
cl.exe @C:/DOCUME~1/STILLW~1/LOCALS~1/Temp/RSP5.tmp/n
~vcecho!Linking.../n
link.exe @C:/DOCUME~1/STILLW~1/LOCALS~1/Temp/RSP6.tmp/n

可以看到這裏只有兩個選項-e和-m,當然還會有其他的,後文再說

其中-e 1380中的參數1380是IDE的進程句柄或者管道句柄。-m後面帶的參數比較長,也是有規律的,據觀察,他們以'/0xa'作爲分割符,~vcecho!也是一個關鍵字,它表示後面的在/n之前的字符串將被輸出到IDE的輸出窗口裏,這樣我們在編譯的過程中也就看到了Compiling resources...、Compiling...、Linking...這些表示編譯進程的信息,類似~vcecho!的詞還有~vctime!和~vcsleep!,我想不用多解釋就明白它們是什麼意思了。

下面看由'/0xa'分割得到的其它三句:

rc.exe /l 0x804 "/foRelease/SSDowner.res" /d "NDEBUG" "D:/Microsoft Visual Studio/MyProjects/test/test.rc"

cl.exe @C:/DOCUME~1/STILLW~1/LOCALS~1/Temp/RSP5.tmp

link.exe @C:/DOCUME~1/STILLW~1/LOCALS~1/Temp/RSP6.tmp

vcspawn將把這些做爲命令行分別建立新的進程。在這裏,很明顯只有rc.exe給出了比較詳細的鏈接參數,也難怪因爲一般資源文件只有一個就夠了,而源文件和目標文件會有多個,於是cl.exe和link.exe的參數中只有它們的臨時文件,這些臨時文件RSP5.tmpRSP6.tmp(名稱隨機)的內容大致如下:(在IDE清理刪除它們之前拷貝過來的):

RSP5.tmp

/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Fp"Release/test.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c
"D:/Microsoft Visual Studio/MyProjects/test/main.c"

RSP6.tmp

kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:no /pdb:"Release/test.pdb" /machine:I386 /out:"Release/test.exe"
"./Release/main.obj"

"./Release/test.res"

分別是編譯器(cl.exe)和鏈接器(linke.exe)的參數,熟悉命令行編譯鏈接的對這些應該很熟悉。

vcspawn除了-e和-m這連個參數外,還有-t -p(一般放在一塊),甚至在你點擊“execute”(執行)的時候,也並不是由IDE去直接執行連接後的可執行文件,而還是由vcspawn作爲中轉,vcspawn啓動可執行文件的參數如下:(這個bill也不告訴俺)

vcspawn.exe -t -p 'D:/Microsoft Visual Studio/MyProjects/test/Release/test.exe"

這個就可以解釋爲什麼在IDE下點擊“execute”去執行編譯後的程序後都會有"Press any key to continue"這句,而且在按了一個鍵後才結束,這些在我們的程序中並沒有這些,這些都是位於vcspawn.exe中的,這也是初學者直接點擊一個自己寫的console程序後看到屏幕一閃而過的原因(當然並非所有的程序都這樣)

3.逆向寫兼容的vcspawn

在通過閱讀vcspawn的反彙編代碼瞭解其大致流程後,就開始了俺的逆向重構的過程,用的是C,由於嚴格按照vcspawn的反彙編代碼的邏輯來寫的,所以花了我近一天的時間,力求做到邏輯上的一致(甚至是彙編代碼級別上的,吹牛啦),由於VC6.0的vcspawn的版本是6.00的,因此自己寫的兼容的vcspawn在vc6.0和evc4.2上工作的很好(放在我機器D:/Microsoft Visual Studio/Common/MSDev98/Bin這個目錄裏,覆蓋原版),不禁竊喜,vc2003的看了一下,也無多大區別(參數有點區別),已無興趣再做重複的事情。

vcspawn大都調用的都是msvcrt這個庫的東西,而且是多線程動態鏈接的(/MD),編譯連接後體積只有7.5k,可謂小巧。

4.這個有什麼用?

是啊,有什麼用呢,在我自己寫的vcspawn中我實現了輸出那些編譯鏈接的細節,就差沒把臨時文件拷過來了(這個不難),其它的可以在其中加入自己要執行的命令或者輸出一些更詳細的信息。不過說過來好像還是無大用處,不過使我自己獨自的弄明白了IDE到底幹了些啥,順便練了下逆向工程

 

最後附上源代碼及編譯好的可執行文件http://www.cppblog.com/Files/aganno2/vcspawn.zip

 

 

發佈了27 篇原創文章 · 獲贊 25 · 訪問量 33萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章