32位汇编第七讲,混合编程,内联汇编
32位匯編第七講,混合編程
博客園IBinary原創 QQ:2510908331? 博客連接:http://www.cnblogs.com/iBinary/
轉載請注明出處,謝謝
混合編程的概念,有時候我們會想,C語言可不可以調用匯編的函數,或者反過來調用
或者說C語言里面內部直接內聯匯編去編寫.
可以實現,靜看怎么實現
?
一丶C語言調用匯編語言的函數
1.創建工程和代碼
①創建VC++控制臺程序
FILE(文件) - NEW (新建)
?
?
?
然后我們打開源文件,一級一級展開,找到我們的main函數
?
?
那么我們現在要調用匯編寫的,那么我們用匯編寫一個代碼
②,創建匯編程序
創建匯編程序,這個比較簡單,我們新建個文件夾,里面新建一個文本文檔,后綴名改為ASM,然后用RadAsm打開,開始編寫代碼
?
?
使用RadAsm編寫,這樣比較快
編寫我們的匯編代碼
?
?
,注意下方的end結束符號,我們并沒有指明開始位置是MyAdd,也就是說這個匯編程序,只能編譯
編譯出的OBJ 和我們上邊寫的程序的OBJ 一起連接(上面的程序也是編譯,不連接)
看下匯編代碼
.386.model flat,stdcalloption casemap:none.const.data.codeMyAdd proc c ,n1:DWORD,n2:DWORDmov eax,n1add eax,n2retMyAdd endpEnd?博客園IBinary原創 QQ:2510908331? 博客連接:http://www.cnblogs.com/iBinary/
③丶C/cpp文件調用匯編中的MyAdd函數
1.先編譯匯編程序,產生obj文件
?
?
將此obj文件復制到我們的C/c++的目錄下
2.修改C/c++程序,調用我們的增加函數
?
?
?
C/C++代碼如下,注意這樣寫你只能編譯,不能連接,只能先生成OBJ
?
博客園IBinary原創 QQ:2510908331? 博客連接:http://www.cnblogs.com/iBinary/
2.連接程序使用的幾個步驟
我們要想使用上面幾個程序,有多中方式去掉用,分別是
①丶手工編譯C/C++程序,產生.obj文件,然后和匯編的.obj連接起來
編譯我們的.cpp文件,產生.boj文件
命令是 cl /c 文件名
?
?
?
,然后把上面的MyAdd.obj(匯編程序編譯的)
匯編程序的編譯可以通過RadAsm,如果配置好了就直接F5編譯即可,如果沒配置好,可以手工用命令行編譯,這里不講解了,以前課程都有講怎么編譯,還有配置RadAsm
現在我們拿到了兩個.obj文件
開始連接成一個.exe文件
手工連接
Link C/C++文件名.obj 匯編文件名.obj
理論上來說連個obj文件誰在前誰在后都沒有區別,但是現在是我們的C/C++程序要調用 MyAdd,所以C/C++在前
打開CMD定位到我們的目錄下(怎么打開百度搜索)
?
?
你可以直接文件夾上面輸入CMD 回車,則會在當前的目錄下,注意這里為了演示命令的截圖
把兩個obj文件拷貝了出來
開始連接
?
?
成功生成
?
?
打開程序校驗一下
?
?
可以調用了
②丶將匯編程序的.obj文件,放到C/C++工程的目錄下,利用工程特性,直接連接
我們可以把obj放到VC++中,這樣我們可以直接編譯連接使用,不用手工編譯連接了
?
?
因為VC++6.0的Bug,我使用了一個插件修復,本來可以直接在 File(文件) - > Open(打開)的
解決VC的Bug,這里我直接提供一個Dll,把Dll放在VC++的目錄的上一層,Addins中
操作步驟
1.右鍵屬性打開文件位置
?
?
?
2.返回上一層目錄
?
?
?
3.進入Addins文件夾下,把FileTool.dll拷貝進去
?
?
拷貝FileTool.dll
?
?
4.重新打開VC++6.0(注意管理員權限打開)
在菜單中點擊 ?Tools(工具) -> Customize(定制) -> Add-ins And Macro Files
?
?
選中即可,如果再有問題,可以百度搜索,DLL會打包
上面解決了一個BUG,那么現在看下我們的工程中是否有了MyAdd.obj
?
?
現在編譯連接則可以執行
?
?
③將obj定義為lib去使用
上面我們直接使用的obj,但是這樣不太好,因為obj一多,工程文件就多了,不好維護(當然目的不再這里)
那么我們把obj定義為lib
怎么定義?,可以使用vc++自帶的lib工具,如果配置了環境變量,則直接輸入cmd,跳轉到目錄下,把MyAdd.obj生成為lib
?
?
輸入lib 則會出現這個幫助,如果沒有配置環境變量,那么輸出lib則會出錯,不過一般默認配置了,如果不會配置,請看前邊的配置環境,RadAsm IDE的配置,里面內容一樣
先介紹一下Lib工具的使用把
這個工具很簡單, ?lib 選項(可選) ?文件名(可選)
例如我們要把MyAdd.obj變為lib,則語法是
Lib MyAdd.obj...... (...代表了有多個obj 依次后面填寫即可,注意中間不要加逗號,隔開即可)
?
生成了
遍歷lib 看下有多少obj,著用list語法
語法
Lib /list lib名稱
?
?
,,為了測試C2ASM我也打包了
現在我們可以使用Lib去編程了
現在只需要我們的工程中包含這個lib則可以使用,不用再把MyAdd.obj添加到工程中了
?
?博客園IBinary原創 QQ:2510908331? 博客連接:http://www.cnblogs.com/iBinary/
二丶匯編調用C寫的函數
匯編調用C寫的函數,那么是一樣的,因為.obj都是一樣的
首先看下匯編代碼,匯編代碼應該挺熟悉了,(不熟悉,看下以前的)
.386.model flat,stdcalloption casemap:noneinclude msvcrt.incincludelib msvcrt.lib ;C庫的動態的靜態使用 includelib MyAdd.lib ;lib調用,加載自己的libMyAdd proto c n1:dword, n2:dword.constg_szFmt db "1+2=%d", 0dh, 0ah, 0g_szPause db "pause", 0.data.codemain proc c argc:dword, argv:dwordinvoke MyAdd, 1, 2invoke crt_printf, offset g_szFmt, eaxinvoke crt_system, offset g_szPausemov eax, 0retmain endpend main?
?
注意,因為我們這里使用printf了,我們是動態的靜態使用,什么是靜態的動態使用,前邊已經說過了,不會的請看下前邊的文章
那么現在我們新建個.c文件,里面單獨寫一個函數(不用工程了)
?
?
編譯這個文件,生成.obj,然后和匯編程序的.obj連接,但是注意現在是匯編程序的.obj在前
因為匯編調用這個的obj
當然這兩個obj我們也可以打包成lib使用,上面的匯編程序就是用的打包好的lib
所以這幾個步驟就不寫了,生成lib給匯編程序使用,至于手工的編譯匯編程序,連接匯編程序其實不建議去用了,隨著編譯器的提升,以后加的選項越來越多
手工生成lib
Lib MyAdd.obj ??(MyAdd.obj 是手工編譯的MyAdd.c的文件)
?
?
使用RadAsm編譯連接1.asm程序
?
?
?博客園IBinary原創 QQ:2510908331? 博客連接:http://www.cnblogs.com/iBinary/
三丶匯編DLL的使用
像我們上面的生成的lib只能給C/C++使用,但是別的程序不見得能使用
所以我們寫一個匯編的DLL,給C/C++程序使用
至于C/C++調用dll,那么有兩種方式
一種是使用靜態方式,就是加載dll的靜態lib庫(這個lib庫中保存的是dll名稱)
然后添加個頭文件去使用
另一種是動態的loadlibrary,和GetprocessAddress去使用,動態的加載dll去使用
這里簡單說下第一種,至于動態使用有開發知識的應該會調用,如果沒開發知識也沒有關系
因為咱們這個是匯編,不是再講開發,(雖然開發很重要),但是咱們今天的主要內容不是上面所有的,壓軸的在最下面
1.首先利用RadAsm新建一個dll的空工程,填寫以下代碼
?
?
匯編代碼:
.386.model flat,stdcalloption casemap:noneinclude windows.inc.const.data.codeMyAdd Proc n1:DWORD, n2:DWORDmov eax, n1add eax, n2 ;寫一個我們的MyAdd函數retMyAdd endpDllMain proc hModule:HINSTANCE , dwReason:DWORD, lpvReserved:LPVOIDmov eax, TRUEretDllMain endpend DllMain ;注意DLL的入口點要指定?
然后在DEF文件導出我們的定義的代碼
?
?
編譯連接之后則會生成DLL,和保存DLL信息的lib
?
?
那么我們的工程可以使用了
靜態使用
?
?
?
結果
?
?
至于代碼,會上傳課堂資料中
博客園IBinary原創 QQ:2510908331? 博客連接:http://www.cnblogs.com/iBinary/
四丶壓軸的內聯匯編
1.內聯匯編簡單了解
首先我們會想,上面雖然完成的 匯編和C的互相調用,也解決的跨語言的DLL調用
但是覺著還是不好,為什么,因為可能我想寫的匯編代碼就那么一點,我還得生成DLL
或者生成lib
那么我們突發奇想,可不可以在C/C++中寫匯編代碼
比如我們寫個int 3的中斷指令
C/C++代碼
?
#include "stdafx.h"typedef int (*PFN)(int n1,int n2); //定義函數指針int main(int argc, char* argv[]){//寫二進制代碼 unsigned char Code[] = {0xCC, 0x55, 0x8B, 0xEC, 0x8B, 0x45, 0x08, 0x03, 0x45, 0x0c, 0xc9, 0xC3};int result = ((PFN)(void*)Code)(1, 2);printf("%d",result);return 0;}?
看到這個代碼是不是暈了,沒關系,誰叫我們是學匯編的,用OD調試看下
?
因為是Dbg程序,所以int 3指令對齊了,我們發現確實是斷點到這里停止了,我們需要價格ret
直接打開int 3.exe看看是否會崩潰,如果崩潰則用OD調試,看下到底出現了什么情況
?
?
調試看看
?
?
發現是int3斷點斷下來了,我們發現,剛在我們寫入的代碼其實是二進制代碼我們把它當做函數執行,也就是Call一下,我們寫入的是一個加法的函數
難道匯編代碼都要這樣寫嗎
所以VC++6.0為我們提供了一個語法,叫做
_asm ?注意前邊是一個下劃線
?
?
也可以加塊語句去寫
?
?
但是一般我們不這樣寫,因為這樣會破壞寄存器環境所以開始和結束我們要保存一下寄存器的環境
?
?
Pushad 和push s是保存所有寄存器環境,和所有標志寄存器標志
我們看下VC++6.0的匯編到底做了什么
(在VC++6.0中內聯匯編,可以下短點,然后ALT +8跳轉到VC的匯編中查看)
?
?
?
?
是一樣的
2.內聯匯編調用函數
一丶普通調用的無參數調用
上面我們知道的怎么寫內聯匯編了,那么下邊我們則可以把這個內聯匯編定位為函數
寫個ADD函數把
首先我們工程封裝成一個函數
?
?
我們可以直接這樣寫,因為編譯器內部已經幫我們壓棧,平棧...各種東西都幫我們做了
我們一會ALT + 8看下
現在我們要調用了,因為返回值問題,是怎么返回我們不知道,雖然我們知道是放在eax中
但是如果你改成int,那么我們要寫為 return eax?顯然是不可以的,而如果在_asm中
寫ret,那么這個函數不知道你返回了所以先定義為void,我們一會解決返回值問題
調用:
?
?
我們要自己push,自己Call,又因為MyAdd是C調用約定,所以我們要自己平棧,
我們看下匯編代碼
這個是我們調用的代碼
?
?
我們看下MyAdd的時候里面做了什么
?
?
我們發現其實我們的核心代碼就是兩句,但是編譯器幫我們做了很多事
從第一個循環申請局部變量上面就不說了,前邊講過了
(保存棧底,開辟局部空間,保存環境.....)
主要看下面,恢復完寄存器信息之后就開始釋放局部變量空間,然后在Debug版本下會檢測棧
是否平衡,如果不平衡,就彈個錯誤框,最后ret的時候,因為壓入了兩個參數還沒有平棧
所以上面我們需要自己平棧,一個參數4個字節,所以+8
看下結果
?
?
?
2.解決普通的調用有返回值的問題
上面我們如果調用,那么就要自己內聯,自己調用,但是很不方便,所以我們加個返回值
直接調用也可以,編譯器智慧給警告,因為編譯器支持這個語法
調用
?
?
?
直接調用即可
看下結果
?
?
那么就完美解決了
博客園IBinary原創 QQ:2510908331? 博客連接:http://www.cnblogs.com/iBinary/
3.(inline)裸函數
我們這樣想,上面編譯器幫我們做了很多事情,我們不知道,我們有的時候這個函數就行自己用我們的寫的代碼
那么這個時候就可以用裸函數了,有關鍵字
_declspec(naked) ....
?
?
看下反匯編是什么
?
?
?
?
可以看到,明顯的編譯器沒有幫我們做申請局部變量空間....等等一系列的操作
但是我們就要自己去寫了
看下結果
?
?
?
4.內聯調用API
如果內聯了,那么就不支持invoke這種偽指令去操作了,都是真實的去寫匯編代碼
?
?
調用其實挺簡單,加上數據段,和函數名就可以的,但是注意函數的頭文件要包含(Windows.h)
5.內聯尋找函數的參數
我們上面調用一個Add函數,自己還要計算
?mov eax,[ebp +8]
?Sub eax,[ebp + 0ch]
但是其實這些我們的函數有參數了,我們可以使用參數來弄
比如
Mov eax,n1
Sub eax,n2 這樣去寫就行
反正怎么像偽指令怎么寫,不支持也要想辦法優化.
不然參數多了就容易混亂
?博客園IBinary原創 QQ:2510908331? 博客連接:http://www.cnblogs.com/iBinary/
?
課堂資料:
鏈接:http://pan.baidu.com/s/1jIJzsyE 密碼:dtu4
?
轉載于:https://www.cnblogs.com/iBinary/p/7555503.html
總結
以上是生活随笔為你收集整理的32位汇编第七讲,混合编程,内联汇编的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HTML-CSS背景渐进色
- 下一篇: 文件排版,较难的线性dp