走进汇编的世界

走进汇编的世界

先来说一下问什么要学点汇编?首先来说一下尽管汇编不是我们熟悉的编程语言,但是终归还是语言,起码我们不用再和0,1打交道了!对于大部分,也包括我自己了,平常接触的都是高级语言,比如C#,C,C++,这些语言都是经过了各位大牛们多年的努力,经过多层的封装,才能让我们享受这样的待遇.这样一来,我们在平时的开发过程中,可以省去很多底层的麻烦,试想一下,如果你在写一个方法的时候,你还需要操心哪些变量放在了寄存器,哪些变量放在了主存,放在寄存器的话又该放在哪一个里面,放在主存的话又该放在那个内存区域等等这一类底层的问题,以及还要考虑各种各样的寄存器名称和他们的作用等等诸如此类的事,估计写个hello,world你也会崩溃的.

因此这不难看出,高级语言给我们带来了很大的便利,但是事情总有两面性,这样所带来的便捷的同时也引发了一些问题.这是因为我们看到的代码,在实际执行它们的时候,可能已经面目全非了,所以很多时候会造成一些莫名的问题发生.

在这里我引用一个大牛写的JAVA代码:本屌不懂java,旨在说明问题

public class Main

{

  public static void main(String[] args)

  {

      Integer a = 127;

      Integer b = 127;

      Integer c = 128;

      Integer d = 128;

      System.out.println(a == b);

      System.out.println(c == d);

  }

  

}

相信懂JAVA的你,肯定能看懂,觉得应该属输出两个true就对了.可是这个程序就是不和人一样,输出了一个true和一个false,如果不信自己试一下.至于原因是啥,各位有兴趣的话自己研究以下JAVA的自动拆装箱,,另外再来看一下Integer对象的ValueOf()方法缓存的范围,答案就会自动的揭晓.

 

产生这个问题的根本原因,其实还是因为编译器给开发者带了一个头套,导致一些开发者知其然不知其所以然,他们根本不清楚自己写出来的程序,实际上是如何运行的(我也不懂).这样的一个头套注定会降低开发者的水平,所以为了提高自己,我们有必要解开这层头套.对于C/C++的开发者来手,揭开头套其实就是了解汇编语言的过程.

 

汇编语言对于C/C++程序员来说,就像class文件对于java程序员一样,因为他们都是编译器处理之后的产物,我们可以从下图中简单的了解一下两者的关联

 

这个图应该很简单吧,说了好多就想说一件事,就是了解汇编的知识对于我们的开发有着不可或缺的好处,尤其是从事C/C++的程序员来说,好处更是无穷的.

 

可能有的朋友会问,俺们是靠Java吃饭的,了解汇编是不是有点多余,毕竟java语言离汇编差的有点远.毕竟java要先编译成class文件,然后交给虚拟机的执行引擎,而虚拟机的执行引擎则是由C/C++来实现的,C/C++有需要经过预处理和GCC编译器的编译才能最终成为汇编语言.乍一看,java确实离汇编比较远.

 

无论你处于一个什么岗位中,哈市无论你将来想从事什么岗位,只要你做的事是指挥计算机帮助你完成一些任务,那么你就有必要了解计算机是如何帮你完成这些事情的,否则你就只会只会,而不懂得如何去做.不知道如何去做的后果就是不知道如何做才能做得更好,反映到现实中,就不你不知道如何写出更好的程序.这点不哪里接,试想一下,你都不知道你的程序实际上是如何运行起来的,你又怎么可能知道怎么写是更好的呢?

 

 

 

初次体验汇编

在编译一段C语言程序的过程中,其实做了很多步骤,比如预编译处理,编译处理,汇编处理以及链接处理.我们要了解的汇编语言,就是在编译处理后的产物,因此我们可以在GCC的编译器当中加入一些参数来控制它生成汇编语言,而不进行汇编处理和链接处理.

我们来看这样一段C语言代码,假设为sum.c文件

int simple(int *xp,int y){    int t = *xp+y;    *xp=t;    return t;}

使用GCC编译器加-S参数来编译这段代码,最终我们可以得到一个sum.s文件,我们使用cat命令来查看一下.(这是linux上的知识,不了解没关系)

.file    "sum.c"

    .text

.globl simple

    .type    simple, @function

simple:

    pushl    %ebp

    movl    %esp, %ebp

    subl    $16, %esp

    movl    8(%ebp), %eax//这一步是从主存取变量xp

    movl    (%eax), %eax//*xp的值

    addl    12(%ebp), %eax//计算*xp+y,并存到%eax寄存器

    movl    %eax, -4(%ebp)//*xp+y赋给变量t

    movl    8(%ebp), %eax//再取xp

    movl    -4(%ebp), %edx//t

    movl    %edx, (%eax)//执行t->*xp

    movl    -4(%ebp), %eax//t放入%eax准备返回

    leave

    ret

    .size    simple, .-simple

    .ident    "GCC: (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3"

.section    .note.GNU-stack,"",@progbits

 

输出啥结果不重要,这里我们主要是看一下汇编语言是如何藐视我们的计算过程的,注释也加上了,来大致描述上面的程序的计算过程.其中需要说明的是,%开头的位寄存器,有小括号的位主存.


熟悉GCC的朋友们应该知道,我们可以控制编译器的优化级别,因此我们使用另外一种方式来编译以下sum.c,我们在-Sde基础上再加一个-O1的参数.之后再次使用cat打开sum.c文件.

.file    "sum.c"

    .text

.globl simple

    .type    simple, @function

simple:

    pushl    %ebp

    movl    %esp, %ebp

    movl    8(%ebp), %edx//xp

    movl    12(%ebp), %eax//y

    addl    (%edx), %eax//计算*xp+y并存到%eax寄存器,准备返回

    movl    %eax, (%edx)//*xp+y存入*xp

    popl    %ebp

    ret

    .size    simple, .-simple

    .ident    "GCC: (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3"

.section    .note.GNU-stack,"",@progbits

 

应该能看出来,汇编指令的数目急剧减少,上面也有注释.从主食中应该能够看出来,这里的优化主要是去掉了变量t的存在,因此减少了指令数.

 

如何像我似得,看不懂汇编,暂且没关系,这里只想让各位体验一下汇编的风格,以及亲自接触一下汇编语言,我们的目的并不是搞清楚它的意义.

 

 

小小的结一下

如果我有不对的地方希望有大神能够指针,毕竟本屌也是个菜鸟!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值