汇编基础

寄存器

CPU 只负责运算,不负责存储数据,而数据都存储在磁盘中,磁盘速度无法满足运算时的速度,因此需要将数据先读取到内存中,CPU 需要的时候就去内存中读取,但 CPU 的运算速度远高与内存的读写速度,为避免被拖慢,CPU 都会自带一级、二级甚至三级缓存。基本上,CPU 缓存可看作是读写速度较快的内存。

但是,CPU 缓存的速度还是不够块,数据在缓存中的地址也是不固定的,CPU 每次读写都需要寻址也会拖慢速度。因此,CPU 自带寄存器(register) 用来存储常用的数据。CPU 优先读写寄存器,再由寄存器与内存交换数据。

寄存器 不依靠地址 来区分数据,而依靠名称每一个寄存器都有自己的名称,通过告诉 CPU 去具体的哪个寄存器读写数据,这样速度是最快的。寄存器被比喻成零级缓存。

寄存器总类

早期 x86 CPU 只有 8 个寄存器,每个都有不同用途,现在的寄存器已经有一百多个了,都变成了通用寄存器,不特别指定用途,但早期寄存器的名字被保留了下来。

以上 8 个寄存器中,前 7 个都是通用的, ESP 寄存器有特殊用途,用于保存 Stack (栈) 的地址。

32 位 CPU 、64 位 CPU 指的是寄存器的大小,32 位 CPU 的寄存器大小是 32 Bit (4 Byte), 64 位 CPU 的寄存器是 64 Bit (8 Byte)。

内存模型

寄存器只能存放很少量的数据,大多数时候, CPU 需要指挥寄存器直接与内存交换数据。而内存存储数据使用的是Heap (堆) 和 Stack (栈) 两种模型进行存储。

Heap (堆)

程序启动时,系统会给程序分配一段内存,用来存储程序和运行产生的数据,这段内存具有地址较低的起始地址和地址较高结束地址。

程序运行中,对于动态的内存占用请求(如新建对象),系统会从程序启动时分配的内存段中,从起始地址开始划分出请求大小的内存段来给用户,若需要更多内存段,则从前面的结束地址开始再堆积。

这种由用户主动请求划分出来的内存区域叫 Heap (堆) ,它由起始地址开始从低位地址向高位地址增长,Heap 的一个重要特定就是不会自动消失,必须手动释放,或由垃圾回收机制来回收。

Stack (栈)

Stack (栈) 是函数运行而临时占用的内存区域。系统开始执行函数时,会在分配给程序的内存段中建立一个帧 (frame) ,函数中所有的内部变量都会保存在这个帧中,函数结束时这个帧会被回收,释放所有内部的变量,不再占用空间。

当函数调用另一个函数时,执行到调用函数时,系统会新建一个帧用于存储新函数的内部变量,这时就同时存在两个帧。一般来说,调用栈有多少层,就有多少帧。当被调用函数运行结束,它的帧就会被回收,系统会回到原函数中断执行的地方,继续往下执行。这种机制实现了函数的层层调用,且每层都能使用自己的本地变量。

所有的帧都存放在 Stack ,由于帧是一层层的堆叠,所以 Stack 被译为具有存储属性还有堆叠特定的 。生成新帧,叫 入栈 (push) ,栈的回收叫 出栈 (pop) 。Stack 的特定就是 后入栈的先出栈(最内层的函数调用,最先结束运行) ,这就是 后进先出 的数据结构。每一次函数执行结束就自动释放一个帧,所有函数执行结束,整个 Stack 就都释放完。

Stack 由内存区的结束地址开始,从高地址向低地址分配,当新的帧产生时新帧地址会往低地址方向移动。

Stack 为什么叫栈

Heap 在词典中翻译 n. 堆,许多 ; vt. 使成堆 , Stack 在词典中翻译为 n. 堆,叠,垛 ; v. 堆积 ,内存模型为什么要将 Heap 译为 , Stack 译为 ? 内存模型又为什么选择 Heap 和 Stack 来描述内存模型?

为了区分这两 从而找的相近的词 来描述 Stack 。而内存模型中选择 Heap 和 Stack 来描述内存模型则是因为两个模型的特性的,杂乱的堆积和整齐的堆叠,存储货物的栈就是整齐的堆叠。

内存模型中的堆栈与数据结构中的堆栈

内存模型中的堆栈

数据结构中的堆栈

CPU 指令

汇编语言的内容就是一条条的 CPU 指令,通过 CPU 指令完成对数据的处理运算。

常见 CPU 指令集:

一些指令

参考

汇编语言入门教程

既生堆何生栈

内存中的堆栈和数据结构堆栈区别