首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

关于汇编的一些札记

2012-12-20 
关于汇编的一些笔记????????????? 一。首先我想对C语言和汇编语言擅长者致以崇高的敬意。客观来说,要学好C和

关于汇编的一些笔记

????????????? 一。首先我想对C语言和汇编语言擅长者致以崇高的敬意。客观来说,要学好C和汇编确实不易,有话说“普通人用C 语言在3 年之下,一般来说,还没掌握C 语言;5 年之下,一般来说还没熟悉C 语言;10 年之下,谈不上精通”,而对于我,很久以前就试着学习C,但每当看到‘*’和‘&’等有关乎指针的代码时就会从心底里抵触,所以至今接触编程若干年后,不懂C语言深感自己委多算是一个业余的,所以决定奋起直追,一方面,完善自己的知识体系,另一方面,在阅读《深入理解计算机系统》和《TCP/IP详解》卷二时遇到了很多困难,由于通篇太多的汇编源码和C源码,虽然阅读这两本书获益不少,但仍感不足,实属遗憾。

    注:在这里要强烈推荐《深入理解计算机系统》和《TCP/IP详解》,前者从程序员的角度剖析了计算机的整个运行机制,涉及到了处理器体系结构,虚拟存储器和并发编程等经典的计算机观点,只不过使用的是汇编语言,但里面的剖析不一定要全部掌握,仍然可以在程序员的层面给以很多的深入理解,有利于编写更加高效的代码,而对于后者该书卷一是对于各种网络协议的理论分析,而卷二则是完完全全的C语言源码堆砌,对于源码爱好者无非是一道丰盛大餐。

    二。正所谓‘工欲善其事必先利其器’,听前辈说‘学好汇编对于学C会有很大作用’,而也有反对者如‘破解牛人Nisy'认为‘C和汇编没有任何联系’,不管如何,因为C语言还是偏底层,而且是所谓的‘面向内存’,而汇编又是所谓的‘面向CPU’,所以我认为学好汇编还是有利于更好的理解C。所以趁着这段时间看看汇编,不指望能有多深入,只是略微的偏向一点底层。

    三。对于代码,一般分为三个层次,首先是从源码到汇编指令,然后经过编译器生成机器码,而机器码便是计算机所可以看懂的语言。汇编指令本质上就是一套指令集,汇编的一个缺点就是平台性太强,某一套指令集只能适合于特定的体系结构和处理器,汇编指令分为(1)汇编指令(2)伪指令(3)其他符号

    在这里先描述一下CPU执行指令的一个过程:

    (1)CPU先从CS和IP中分别取出段地址和偏移地址

    (2)再把得到的以上两个地址放入地址加法器得到内存地址

    (3)再通过地址总线把得到的以上的内存地址传入内存并得到相应的数据

    (4)再把得到的以上的数据通过数据总线取出传到指令缓冲器

    (5)指令缓冲器作为一个队列依次执行指令,最后把结果放入相应的寄存器如AX或BX

    上面这个过程基本描述了CPU的工作机制,在这里再说明一些基本概念:

    (1)CPU内部组成:

        寄存器:有通用寄存器如AX,CX,段寄存器DS,CS

        运算器:只存在加法,对于减法可以使用补码,对于乘法可以使用多次加同一个数,对于除法可以使用多次减            同一个数

        控制器:控制对数据的读或者写

    (2)CS和IP:

        对于单核CPU,CPU同一时刻只能执行一条指令,这就是为什么宏观上的并发只是因为在有‘操作系统’这一层面的情况下,操作系统对于软件资源和硬件资源的分配,在分配合理并且CPU执行指令速度非常快的情况下给人以假象‘每一个程序都有自己的CPU’,这也就是为什么我们可以一边玩着游戏一边听着音乐,回到正题,那么CPU如何才能知道即将要执行的指令的地址呢?CPU使用了两个寄存器来处理,分别是CS段寄存器和IP偏移地址寄存器,在这再说明一点‘物理地址=段地址X16+偏移地址’,所以这时从CS和IP中取出送到地址加法器中算得物理地址,然后IP根据所读取指令的长度进行自增从而指向下一条指令。

    (3)地址总线,数据总线和控制总线

        地址总线:CPU的地址总线为16条,CPU是通过地址总线来指定存储单元的,所以地址总线传输地址的能力即             为CPU的寻址能力

        数据总线:数据总线的宽度决定了CPU与外界数据的传送速度

        控制总线:要么是读,要么是写

    四。物理地址的表示方法:

    物理地址=段地址X16+偏移地址

    因为8086CPU内部为16位地址总线,而CPU外部则为20位地址总线,为了利用到外部更多的地址总线,所以使用了‘物理地址 = 段地址 X 16 + 偏移地址’这种方法,在这里‘X 16’ 就是向左移一位,即变为了20位地址

    五。栈:

    之前在《数据结构》的总结日志上也有对栈进行了解,无非就是‘先入后出’的一种数据结构,但是对于汇编来说,这确实一种非常重要的概念,出于模块化编译的要求,出现了栈机制,如:

    firstMethod(){

        ?? int i = 0;

        secondMethod();

       ????? printf("%d,i);

    }

    在这里使用C语言来描述,因为对于汇编如loop,ret,jmp等指令不算熟悉,在执行firstMethod中,要执行secondMethod,在执行完secondMethod后,要接着执行printf方法,在内存中,实际上在要执行secondMethod时,先把之后要执行的代码即printf的内存地址即段地址和偏移地址压入栈中,在执行secondMethod完毕后,再从栈中弹出最顶的地址即得到需要继续执行代码的内存地址,从而继续执行firstMethod方法体,了解操作系统的人可能这时会想到进程,确实如此,在操作系统层面这种行为被称为‘上下文切换’,但这里大家可以不用考虑操作系统层面,也不用考虑到高速缓存这一层面,简单的理解为‘CPU和内存的交互’可以更好的理解问题。

    栈操作无非为入栈PUSH和出栈POP,在CPU中何以知道栈顶的位置,同样,CPU使用了段寄存器SS和寄存器SP,栈顶的段地址存放在SS,栈顶的偏移地址存放在SP,对于PUSH和POP,修改的只是SP的值,如

    PUSH AX???将AX的内容入栈:

        (1)SP = SP - 2,此时SS:SP指向新的栈顶

       (2)把AX的内容送入SS:SP所指向的内存单元处

    POP AX???? 将栈中数据取出放入AX,

        (1)将SS:SP所指向的内存单元处得内容取出放入AX中

        (2)SP = SP + 2

  

    另外对于汇编中的中断亦使用了栈机制,而对于黑客来说,‘栈溢出’攻击则为最常用的一种恶意攻击,使用的便是SP指针超出了栈范围,从而指向了一段非安全的内存空间,使得黑客有机可趁。

    六。最后扯点别的。

    在C语言中,prinf使用的很频繁,在这里从汇编语言的角度来看该方法的本质。

    在计算机中,内存空间被分为了很多块:(1)主存地址空间(2)显存地址空间(3)各类ROM地址空间

    显存地址空间有这样的特点,即只要向该地址空间写入数据,该数据马上显示到显示器,对于具体的细节应该是由显卡来处理的吧,之前有听说过IE9使用GPU加速,GPU这个本来很旧的概念被热炒,在这里不多说GPU的运行机制。

    所以说,printf的本质无非是显存地址空间的一种特性,或者说计算机设计者就是这样设计的,本身过程是很简单的,就有点像面向对象中的接口,你只要按照接口的要求往里面传入标准化的数据,之后该怎么处理已经与你无干了,在这里就是你只管把printf的内容传入显存空间地址,它自会处理然后显示在显示器。

    七。对于汇编语言。自感难度非常大,自己也是时间原因没有进行实质性的编码,我也不指望有多么深入的了解,只当是更加深入地理解计算机运行的机制以及为学习C语言作一个铺垫,所以以上的内容即学习笔记权当是一次文字记录,多有疏漏以及错误,在这里欢迎牛人拍板砖,正所谓板砖越多成长越快。

    不说了,看《非诚勿扰》!

热点排行