masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

Editor發表於2018-02-23

概覽:本文做了個Demo測試小程式來體現masm32開發包的庫與VC6.0存在的一些不相容的問題,如下即為所描述的問題及列舉的對應的解決辦法:

1、在RadASM環境下連線VC6.0生成的.obj時,找不到_main符號的問題及解決辦法。

2、VC6.0對GetEnvironmentStrings這個函式的ASCII版本和UNICODE版本的巨集替換與masm32的不一致的問題及解決辦法。


一、Bug的觸發


建立VC6.0工程,宣告和定義ShowHello()函式,然後編譯生成.obj目標檔案:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

masm32開發包與VC6.0之間存在的Bug的體現及解決辦法


建立RadASM控制檯工程。由於VC6.0編譯好的程式碼都會被生成在.obj裡面,所以就能在RadASM工程直接呼叫.obj裡面的函式。將編譯好的StdAfx.obj扔到RadASM工程資料夾下,並新增到RadASM工程裡面。然後就可以呼叫了,以下就是呼叫ShowHell()這個函式。


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

編譯可通過,但是連線的時候報了兩個錯誤:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法


二、錯誤一


提示缺少_main符號,為什麼會缺少_main符號?是因為在VC6.0生成的.obj會把LIBCD.LIB一塊連線進去(LIBCD.LIB在VC6.0安裝目錄的VC98下的LIB資料夾裡面)。在 LIBCD.LIB中有一個crt0.obj,這個crt0.obj就是VC6的入口程式碼,我們用IDA開啟LIBCD.LIB檢視:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

雙擊這個crt0.obj進去後發現,就會看到的即是VC6.0的入口程式碼:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

入口程式碼做完一些初始化工作後,就呼叫了main函式


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

由於連線了LIBCD.LIB,而LIBCD.LIB又有入口函式被連線,而拷貝到RadASM工程下的StdAfx.obj並沒有入口函式的定義,於是就報錯第一個錯誤:缺少_main符號。


解決辦法一:將RadASM的程式入口改為main:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

再連線,第一個錯誤解決了!


解決辦法二:直接定一個的空函式,使RadASM連線時能檢測到_main符號:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

這個方法同樣可以解決第一個錯誤!


三、錯誤二


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法


缺少一個函式定義:__imp__GetEnvironmentStrings

       

首先,在VC6.0下我們看看GetEnvironmentStrings這個函式在何時被呼叫。通過棧回溯定位到VC的mainCRTStartup,然後往下就會看到:是mainCRTStartup呼叫了這個函式:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

關鍵點:在RadASM連線時會報錯,是由於識別不出.obj下的這個函式,即masm32對這個宣告的與VC6.0宣告的不一致。


問題的體現:

1、我們先看masm32對ASCII與UNICODE版本的實現。開啟masm32的include目錄,找到kernel32.inc


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

開啟並定位到GetEnvironmentStrings這個函式:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

masm32呼叫該函式時如果是ASCII版,則用GetEnvironmentStringsA巨集替換,如果是UNICODE版,則用GetEnvironmentStringsW巨集替換。


 2、再看微軟對ASCII版本與UNICODE版本的實現,首先我們以舉MessageBox為例子:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

 但是很不幸的是GetEnvironmentStrings這個函式並不這樣子:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法


這時就發現了,字尾帶A的GetEnvironmentStringsA的是ASCII版本,而帶W的GetEnvironmentStringsW是UNICODE版。也就是說帶GetEnvironmentStringsA的是巨集,而GetEnvironmentStrings才是函式。


通過對比發現,問題很明顯的體現了,masm32與微軟VC6.0對此函式的宣告不一致,才會導致上面說的RadASM連線此函式時報的那個錯誤!!


解決辦法一:先修改masm32處的宣告:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

 修改完儲存,但是此時連線依然是不會過的,因為.lib已經打包了kernel32.inc。簡潔的解決辦法,可直接拿VC6.0下的.lib直接覆蓋masm32下的這個.lib,這是一種解決辦法。我們就試著將它拷到masm32的.lib目錄下:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

然後,在RadASM工程下再次連線:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

這樣連線就過了。但此時程式依然不能執行,由於我們給RadASM提供的.obj是VC環境下編譯的.obj,所以對應的入口函式也應改為mainCRTStartup,即:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

此處,再編譯、連線、執行,即可看正常執行。


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法


解決辦法二:除上面提供的方法外,還有另外的解決辦法:將修改後的kernel32.inc重新生成.lib檔案替換原來的.lib。我們使用masm32提供的工具inc2l來重新生成kernel32.lib。這個工具在masm32的tool目錄下:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

將我們修改過的kernel32.inc拷貝進來:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

開啟命令列,並編譯生成kernel32.lib:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

將重新生成的kernel32.lib拷貝到masm32目錄下的lib資料夾覆蓋舊的kernel32.lib:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

到了這一步,就算大功告成了。將RadASM再做連線,編譯通過了!


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

執行看到效果:


masm32開發包與VC6.0之間存在的Bug的體現及解決辦法

到此,RadASM連線VC6.0時的兩個報錯都解決了。


四、尾聲


此博文是在科銳學習期間的日常筆記,心血來潮就發表了此帖子,對此有遺落的地方望各位大佬指出供小弟加以改正。最後感謝看雪提供的平臺使大家有相互學習的機會!


本文由看雪論壇 小鐘 原創 轉載請註明來自看雪社群

相關文章