標 題: 【原創(chuàng)】內聯(lián)匯編
作 者: kflnig
時 間: 2007-02-11,15:27:26
鏈 接: http://bbs.pediy.com/showthread.php?t=39485
有很多人認為匯編已經失去了用武之地,包括曾經的我。我用的是visual c++6.0?,F(xiàn)在我要問你一個問題。
a=10,b=20。你現(xiàn)在要使a和b的值交換。你有什么辦法。這是教科書上說得很多的方法。第一種方法:
#include <iostream.h>
void main()
{
int a,b,c;
a=10;
b=20;
c=a;
a=b;
b=c;
cout<<“a=”<<a<<“,b=”<<b;
}
輸出當然是a=20,b=10
該方法引入了一個新的變量,即多開辟了一個DWORD的空間?,F(xiàn)在請你再看我的實現(xiàn)方法。第二種方法:(把加了下劃線的部分改成如下代碼)
_asm
{
push a
push b
pop a
pop b
}
我稍微解釋一下:_asm告訴編譯器,我要使用內聯(lián)匯編代碼了。換成__asm也一樣(注意這里有兩根英文半角下劃線,前面的是一條)。上面的那段代碼也等價于
_asm push a
_asm push b
_asm pop a
_asm pop b
看來還是用花括號{}來得方便。
上述,我在c++中使用了內聯(lián)匯編,說實話,這種方法比第一種方法來得差。因為我的兩個push就開辟了2個DWORD空間。
有沒有辦法不開辟額外的空間呢?請看第三種實現(xiàn)方法:
_asm
{
mov eax,a
mov ebx,b
xchg eax,ebx
mov a,eax
mov b,ebx
}
在聽取下面的朋友的批評之后,上面這段代碼不免有脫了褲子放屁之嫌,應改為
_asm
{
mov eax,a
xchg eax,b
mov a,eax
}
這樣看起來就比較好了。因為第一段代碼執(zhí)行的時候也要先把值移動到寄存器中。
要說內聯(lián)匯編最重要的作用就是在寫溢出代碼和注冊機中。如果你有志于學這些東西,那么下面的文章你要好好看了??上У氖莾嚷?lián)匯編不是宏匯編,一些偽指令內聯(lián)匯編中是不能用的,比如說
.if
.elseif
.endif
雖然在很多時候寫代碼不方便了,但是勉強還行。
很重要的一點:一般來說,在_asm塊開始的時候,你不應該假定某個寄存器中包含著值。也就是說所有的寄存器都是可用的。當然不指eip,esp,ebp用這些寄存器用得不好你會死得很難看,是cracker都知道這三個寄存器的作用吧!還要注意PUSH,POP配對。這是為了堆棧平衡。
現(xiàn)在基本上我們邁出了學習內聯(lián)匯編的第一步,也是一大步。剩下的都只是一些細節(jié)了。
現(xiàn)在我要編寫一個函數(shù)。
int cmpare(int a,int b)
{
_asm
{
mov eax,a
cmp eax,b
jge line1;都是因為偽指令不能用,否則這里肯定是用.if偽指令更容易看懂。
mov eax,b
line1:
}
}
我寫這個函數(shù)的目的是為了告訴大家整數(shù)在默認情況下是采用eax來作為返回值的,還有就是在內聯(lián)匯編中推薦用匯編自己的注釋符號“;”,雖然說c++的注釋符號也可以使用。這里我的a=10,b=20。雖然在編譯時c++提示我如圖1
圖1
但是真正執(zhí)行cout<<cmpare(10,20)輸出的是20。另外浮點通過st(0)返回值。
sz[1]= 3;
_asm
{
mov eax,sz[1]
mov a,eax
}
cout<<a;
你知道這將會輸出什么嗎?你絕對意想不到,我告訴你,在我這里是63753420。是不是很迷惑。當然開始的時候我也很迷糊,咱們先把mov eax,sz[1]改成mov eax,sz[4]然后再編譯,看現(xiàn)在已經達到了我們預想的情況a=3。至于為什么嗎?原因是:[]是c++和匯編共同包含的操作符,會被編譯成匯編的操作符。而一個int是4字節(jié),所以我們的代碼應該是sz[4]而不是sz[1],后面的下標實際上是起著尋址的作用。前面的數(shù)組名sz是起著基地址的作用。如果不好理解你應該用OD調試看看。為了簡便我們的寫法。我覺得我們可以這樣操作數(shù)組:
sz[xl*lx]。
lx是我們先前就定義的各種類型常量,xl是序列,即一般的下標值。這個類型的常量我們可以用
_asm
{
mov eax,type sz;sz是數(shù)組或者變量名
mov a,eax
}
cout<<a;
這樣就可以輸出這種數(shù)據(jù)的每個數(shù)據(jù)所占的大小了,單位是byte。
內聯(lián)匯編學習的路還很遠,大家要努力學習。
學習匯編,最常用的東西除了寄存器就是指針了,在匯編中指針的反映就是使用[ address]。
不懂事的程序員往往很容易寫出這樣的代碼:
_asm
{
lea eax,a
mov b,[eax]
}
這當然是錯誤的,這反映為對匯編代碼知識不是很了解。因為mov指令是不可以這樣使用的
mov m32,m32;m32表示32位儲存器。所以只是應該改成下面這樣。
_asm
{
lea eax,a
mov ebx,[eax]
mov b,ebx
}
這樣a的值才順利到達了變量b這里。下面再舉幾個例子,只是希望對一些匯編代碼不太熟悉的小鳥一些幫助。我們繼續(xù)。
a=0x120;
_asm
{
lea ebx,a
movzx eax, byte ptr [ebx]
mov b,eax
}
cout<<b;
b等于多少?知道嗎?如果你說的是32,那么你很聰明,匯編學得還不錯。如果你說的是48,那么你已經把整數(shù)變量和字符串混起來了,在ASCII碼表中0的表示就是48。如果你說的是1,那么你應該還不懂匯編。
在內存中ebx指向的內存應該是20 01。因為所有的東西在內存中都是反向存儲的。在計算機運算的時候就是01 20。在出一道練習題
在內存中20 30 04這個值是多少?答案:04 30 20。
這里我們要特別注意的是在寫注冊機時,你得先知道,你輸入的值,它是在當整數(shù)計算,還是字符串計算。通常它取得到的都是字符串,有些軟件會把字符串轉換成整數(shù)。
這么點東西,我學習了一天啊!慚愧,慚愧……
最后夸獎自己一句,這篇文章真的很好,很難找到這么淺顯易懂的文章?。_^