打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
【原创】内联汇编
标 题: 【原创】内联汇编
作 者: kflnig
时 间: 2007-02-11,15:27:26
链 接: http://bbs.pediy.com/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。
这里我们要特别注意的是在写注册机时,你得先知道,你输入的值,它是在当整数计算,还是字符串计算。通常它取得到的都是字符串,有些软件会把字符串转换成整数。
这么点东西,我学习了一天啊!惭愧,惭愧……
最后夸奖自己一句,这篇文章真的很好,很难找到这么浅显易懂的文章啊!^_^                                 
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
AT & T 汇编语法格式(与intel的不同)
x86汇编与C的关系
VC知识库文章 - MMX指令集在C 中的使用
Delphi内嵌汇编语言BASM精要(转帖)
AT&T汇编语言(转)
如何在DELPHI中使用汇编
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服