读书笔记:《深入理解计算机系统》 之 第三章 程序的机器级表示

第一次作业:了解机器代码中的数据格式以及常用的指令

第二次作业:了解程序中的控制和过程

第三次作业:了解数组,其他数据结构,以及如何在机器级程序中将控制与数据结合起来

第一次作业:了解机器代码中的数据格式以及常用的指令

我们常谈程序=数据结构 + 算法 。而汇编语言在我看来就是由数据和操作组成。

首先我们要了解下数据格式,Intel用“字”来表示16位数据类型,所以以此类推,32位数为“双字”,64位数为“四字”。

然后,我们了解下数据存储在哪,1个x86-64的CPU包含一组16个存储64位的寄存器,用来存储整数数据和指针。

一般用%rbp 指向当前运行时栈的开始位置,用%rsp 用来指明运行时栈的结束位置。

然后就是操作,在汇编语言中叫做指令,下面谈几个汇编中常用的指令。

首先,操作数,是指出执行一个操作中要使用的源数据值,以及放置结果的目的位置。

 操作数分为三类

一是立即数,用来表示常数值。

二是寄存器,表示某个寄存器的内容。

三是内存引用,它会根据计算出来的地址来访问某个内存位置。而这样的寻址方式在IA-32中又分为两类

一种是针对操作数:有立即寻址,寄存器寻址,存储器操作数寻址三种方式。

另一种是针对寄存器:相对寻址。

再然后,就是最常用的数据传送指令。

MOV类是最简单的数据传送指令,把数据从源位置复制到目的位置,不做任何变化。

MOV类主要有四条指令组成,movb,movw,movl和movq,这些指令执行相同的操作,主要区别在于它们的操作数大小不同,也就是后缀b,w,l,q代表的字节数不同。

在传送的时候有一个限制,传送指令的两个操作数都不能指向内存位置,将一个值从一个内存位置复制到另一个位置需要两条指令,第一条指令将源值加载到寄存器中,第二条将寄存器值写入目标的位置。

其他还有一些加载有效地址,移位操作,算术操作等指令。

第二次作业:了解程序中的控制和过程

在机器程序中,除了以上提到的可以一条一条指令按顺序执行的情况,还有一些控制类型的跳转指令,比如C语言中条件语句,循环语句,分支语句等类型。

机器代码有两种机制来实现有条件的行为。

一种是控制流,即根据条件进行跳转。

一种是数据流,即把所有可能的条件都计算出来,再进行选择。

在控制流中,处理器会猜测分支是否会执行,虽然有90%,但是有时候会猜错,例如最简单的if-else语句,就有50%的几率猜错,所以性能没有数据流好。

而数据流也存在问题,如果一个分支存在错误,则程序就会崩溃。所以数据流的使用有限制。

最后,再谈跳转指令,跳转指令有几种不同的编码,最常用的都是PC相对的,可以根据当前程序的位置来判断跳转位置。

而机器代码中的过程,它是一种抽象,提供了封装代码的方式,然后在程序中不同的地方还可以调用这个函数。一般可以抽象为三个机制:传递控制,传递数据,分配和释放内存。

第三次作业:了解数组,其他数据结构,以及如何在机器级程序中将控制与数据结合起来

C语言中的数组,以及结构和联合的内存地址的计算方式,其实就是a+bx+cy这种类型的计算。

在机器级的程序中是如何将控制和数据结合起来的?

首先,我们回顾下指针,指针以一种统一方式,对不同数据结构的元素产生应用。其实它的基本概念也可以映射到机器代码上的一些原则。例如每个指针都对应一个类型,每个指针都有一个值等。

然后,C语言中对数组不进行边界检查,所以很容易出现数组越界,会出现缓冲器溢出,而这种漏洞很容易被针对进行攻击,对于这些攻击,也有栈随机化,栈破坏检测,限制可执行代码区域等机制进行应对,但是并不能百分百防护。

最后,关于如何实现函数要求的空间大小在每次执行时都可能不同的情况,其实就是使用了%rbp作为基指针,然后进行偏移量计算,并最后返回存储地址。

发布了41 篇原创文章 · 获赞 15 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/ScanQ/article/details/101175763