1

深入理解计算机系统(3.2)---数据格式、访问信息以及操作数指示符

 2 years ago
source link: https://www.cnblogs.com/zuoxiaolong/p/computer14.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

  本文的内容其实可以成为汇编语言的基础,因为汇编语言大部分时候是在操作一些我们平时开发看不到的东西,因此本文的目的就是搞清楚,汇编语言都是在操作些什么东西。或者更准确的说,各种汇编指令都是在操作什么样的对象。

汇编层次的对象

  在平时的开发过程中,CPU处理器的状态对开发者是隐藏的,我们看不到CPU当中各个对象的状态。但是在汇编语言中,我们可以清楚的看到这些对象的状态,其中CPU主要包含以下几个对象。

  程序计数器(PC):记录下一条指令的地址。

  整数寄存器文件:共8个,可以存储一些地址或者整数的数据。

  条件寄存器:保存算数或逻辑指令的状态信息,可以实现程序的流程控制。

  浮点寄存器:存储浮点数。

  可以看出,这些都是CPU处理器当中的对象,上一章我们写过一个简单的C程序,相信如果不是看了汇编代码,各位也都看不出来在程序运行过程中,CPU当中这些对象都在做着一些什么样的操作,又在存储着一些什么样的内容。

数据的格式

  在上一章当中,几乎所有的汇编指令后面都有一个字母l,比如movl、addl、subl、pushl等等,这个l的后缀其实就是表示的数据格式,表示我们操作的是32位的数值。

  在计算机从16位扩展到32位,以至于当前的64位来讲,数据格式就一直在变。但是历史总会多少影响着未来的走向,因此我们习惯称16位为“字”,而32位则为“双字”,相应的,64位则为“四字”。

  以下我们以IA32架构为例,来看一下各个数据格式对应的后缀是什么。

  图当中已经介绍的比较清楚,LZ这里就不再废话了。需要一提的就是,long long int在IA32架构中是不支持这种数据格式的,因此就没有列出它的后缀。另外,long double是一种扩展类型,通常采用12个字节来表示。

  上面的图示使用的方式很简单,比如mov指令,它是一个数据传送的指令,那么movb就代表传送一个字节的数据,movw就代表传送两个字节的数据,而movl就代表传送四个字节的数据。

  寄存器是CPU当中非常重要的对象,一般情况下,很多临时变量都会存储在这里,就像上一章当中的临时变量t,在优化之后,t将不再进入主存,而只留在寄存器当中。这样可以提高程序运行的速度,因为寄存器的速度要高于主存,而且在寄存器与主存之间传输数据,也是十分耗时间的一件事。

  下面是一张书中的寄存器图示,它基于IA32架构给出。

  可以看到,对于%esp和%ebp寄存器来讲,图中标注了它们分别是栈指针以及帧指针。而对于另外六个寄存器来讲,它们大部分时候是一样的,但是还是有些许的不同。

  比如%eax寄存器,它很多时候用来存储函数的返回值。而对于%eax、%ecx、%edx、%ebx来讲,它们都可以被访问单独的字节。另外需要一提的是,这八个寄存器都可以被访问双字节。

  除了以上的区别之外,对于%eax、%ecx、%edx和%ebx、%esi、%edi来讲,它们的使用惯例也有些许不同,这个在后面我们将深入讨论。这里各位只要大概认识一下这八位神仙就行了。

操作数指示符

  操作数指示符这个称谓是书上给的,但LZ觉得这个概念不太容易理解,操作数指示符其实指的就是一种取值的标识方式,用来获取参与各种操作的操作数。

  这些标识方式一共有三种,一种是$符号后跟一个标准C表示的整数,比如$100,$0x11等等。第二种则是寄存器,当它作为一个操作数的时候,则是取的寄存器当中的数值。另外,对于寄存器来说,也可以选择性的操作4个、2个、1个字节,而并不一定非要操作4个字节。最后一种,则是我们相对来说最熟悉的,就是存储器或者说内存。当它作为一个操作数的时候,会去计算存储器地址的数值,然后去这个地址取相应的数值。

  对于这三种操作数的标识方式,在书中给出了一个表格,这里LZ贴一下。

  第一列是代表的类型,而第一行则是指的立即数,第二行则是指的寄存器,而剩下的都是存储器了。对于立即数和寄存器来讲,比较好理解,就是直接取值或者取寄存器的值。而对于存储器来讲,则有很多种情况,不过我们也可以看出,上面所有的情况,其实都是最后一种的特殊情况。Imm(Eb,Ei,s)是存储器取值的一般形式,比如当Imm为0时,则是倒数第二种取值方式。对于其它的形式,也可以使用同样的方式推算出来。

  由于存储器相对来说,理解起来比较困难一点。因此这里LZ举个简单的例子,比如对于4(%esp,%eax,4)这个操作数来讲,它代表的是内存地址为4+%esp+4*%eax的存储器区域的值。

  操作数是大部分指令都有的,因此上面的这些标识方式,在之后的文章中我们会经常看到,它们将会成为各位猿友很好的朋友。

  本章只介绍了一些汇编当中基础的知识,这些内容相对来讲不是特别困难,但却是打开后面神秘大门的钥匙。因此倘若有哪位猿友不是太理解本章的内容的话,LZ希望各位可以从实践入手去理解一下本章的内容。这一点可以结合上一章来看,从上一章给出的汇编代码中寻找数据格式、操作数以及寄存器的部分,这应该是十分轻松的,因为上一章的汇编代码中充斥着这三个部分的内容。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK