标 题: 【原创】内联汇编 作 者: kflnig 时 间: 2007-02-11,15:27:26 链 接: http://bbs./showthread.php?t=39485 有很多人认为汇编已经失去了用武之地,包括曾经的我。我用的是visual c++6.0。现在我要问你一个问题。 a=10,b=20。你现在要使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的空间。现在请你再看我的实现方法。第二种方法:(把加了下划线的部分改成如下代码) _asm { push a push b pop a pop b } 我稍微解释一下:_asm告诉编译器,我要使用内联汇编代码了。换成__asm也一样(注意这里有两根英文半角下划线,前面的是一条)。上面的那段代码也等价于 _asm push a _asm push b _asm pop a _asm pop b 看来还是用花括号{}来得方便。 上述,我在c++中使用了内联汇编,说实话,这种方法比第一种方法来得差。因为我的两个push就开辟了2个DWORD空间。 有没有办法不开辟额外的空间呢?请看第三种实现方法: _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 } 这样看起来就比较好了。因为第一段代码执行的时候也要先把值移动到寄存器中。 要说内联汇编最重要的作用就是在写溢出代码和注册机中。如果你有志于学这些东西,那么下面的文章你要好好看了。可惜的是内联汇编不是宏汇编,一些伪指令内联汇编中是不能用的,比如说 .if .elseif .endif 虽然在很多时候写代码不方便了,但是勉强还行。 很重要的一点:一般来说,在_asm块开始的时候,你不应该假定某个寄存器中包含着值。也就是说所有的寄存器都是可用的。当然不指eip,esp,ebp用这些寄存器用得不好你会死得很难看,是cracker都知道这三个寄存器的作用吧!还要注意PUSH,POP配对。这是为了堆栈平衡。 现在基本上我们迈出了学习内联汇编的第一步,也是一大步。剩下的都只是一些细节了。 现在我要编写一个函数。 int cmpare(int a,int b) { _asm { mov eax,a cmp eax,b jge line1;都是因为伪指令不能用,否则这里肯定是用.if伪指令更容易看懂。 mov eax,b line1: } } 我写这个函数的目的是为了告诉大家整数在默认情况下是采用eax来作为返回值的,还有就是在内联汇编中推荐用汇编自己的注释符号“;”,虽然说c++的注释符号也可以使用。这里我的a=10,b=20。虽然在编译时c++提示我如图1 ![]() 图1 但是真正执行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]然后再编译,看现在已经达到了我们预想的情况a=3。至于为什么吗?原因是:[]是c++和汇编共同包含的操作符,会被编译成汇编的操作符。而一个int是4字节,所以我们的代码应该是sz[4]而不是sz[1],后面的下标实际上是起着寻址的作用。前面的数组名sz是起着基地址的作用。如果不好理解你应该用OD调试看看。为了简便我们的写法。我觉得我们可以这样操作数组: sz[xl*lx]。 lx是我们先前就定义的各种类型常量,xl是序列,即一般的下标值。这个类型的常量我们可以用 _asm { mov eax,type sz;sz是数组或者变量名 mov a,eax } cout<<a; 这样就可以输出这种数据的每个数据所占的大小了,单位是byte。 内联汇编学习的路还很远,大家要努力学习。 学习汇编,最常用的东西除了寄存器就是指针了,在汇编中指针的反映就是使用[ 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这里。下面再举几个例子,只是希望对一些汇编代码不太熟悉的小鸟一些帮助。我们继续。 a=0x120; _asm { lea ebx,a movzx eax, byte ptr [ebx] mov b,eax } cout<<b; b等于多少?知道吗?如果你说的是32,那么你很聪明,汇编学得还不错。如果你说的是48,那么你已经把整数变量和字符串混起来了,在ASCII码表中0的表示就是48。如果你说的是1,那么你应该还不懂汇编。 在内存中ebx指向的内存应该是20 01。因为所有的东西在内存中都是反向存储的。在计算机运算的时候就是01 20。在出一道练习题 在内存中20 30 04这个值是多少?答案:04 30 20。 这里我们要特别注意的是在写注册机时,你得先知道,你输入的值,它是在当整数计算,还是字符串计算。通常它取得到的都是字符串,有些软件会把字符串转换成整数。 这么点东西,我学习了一天啊!惭愧,惭愧…… 最后夸奖自己一句,这篇文章真的很好,很难找到这么浅显易懂的文章啊!^_^ |
|
来自: Rainboy913 > 《VC 下的汇编生成与学习》