上篇文章我们了解下CPU寄存机部分基础内容,总是提到内存这两个字,日常工作中也经常会提到内存,现在通过本文来看下内存到底是什么鬼?
内存:计算机系统的存储设备,其作用主要是协助CPU在执行程序时存储数据和指令。
内存由大量存储单元构成,内存单元为一字节(一字节包含八个二进制位),各内存单元都有一个编号,也可理解为各内存单元都有个地址。
在编写汇编代码或编译器把高级语言所写的程序编译成汇编指令时,如需读写内存,则必须在指令中指定内存地址,否则CPU不知道应该读写那个内存单元。
高级语言中都存在变量的概念,而变量又有全局变量以及函数局部变量之分,但不管是哪种变量(除C中申明为register的变量),都需要保存在内存中。
同样的,绝大部分类型变量都不会只占用一个字节大小的内存,但各内存单元只有一个字节大小,这种问题该怎么处理呢?
事实上,任何大于一字节的变量都是存储在相邻的几个内存单元中的,像Go中int64类型的变量在内存中就是存储在连续的八个内存单元中。如需读写该变量,只需在汇编指令中指定这些内存单元的起始地址以及需要读写的字节数就可以了。
接下来又有新的问题了,上面说到int64在内存中占用连续八个字节的内存,那这八个字节如何存储六十四位整型的数据呢?比如如何在内存中存储0x1122334455667788这个16进制表示的整型值呢?
两种方案如下:
-
把高位的0x11放在这8个内存单元的第一个字节。
-
把低位的0x88放在这8个内存单元的第一个字节。
根据上述两种方案,不同的CPU会采用不同的策略,比如X86系列(包括ADM64)的CPU是把低位的0x88放在起始位置,而PowerPC CPU则会把高位的0x11放在起始位置,这其实是大小端存储模式,解释如下:
-
大端存储模式:数据的高字节保存在内存的低地址中,反之亦然。
-
小端存储模式:数据的低字节保存在内存的高地址中,反之亦然。
特别提醒,大小端存储模式与CPU有关,与内存无关,内存只管保存数据,而不操心数据是什么以及怎么解释。
来看下大小端模式存储的示意图:
来用上篇文章聊的CPU存储器时使用的例子拿过来加深对内存和寄存器的理解,如下:
a := b + c
mov (%rsp),%rdx //把变量b的值从内存中读取到寄存器rdx
mov 0x8(%rsp),%rax //把变量c的值从内存中读取到寄存器rax
add %rdx,%rax //把寄存器rdx和rax里面的值相加,之后将结果放回寄存器rax
mov %rax,0x10(%rsp) //把寄存器rax中的值写回变量a所在的寄存器rsp
上述案例第3、4这两条指令跟内存的读写有关,rsp寄存器中存储的是一个内存地址。
现在来假设这个内存地址是X,那么第一条指令就表示从内存地址为X开始的八个内存单元的值读取并写入寄存器rdx(因为rdx是64位寄存器,所以就隐含了要一次性读取连续的八个内存单元,指令中的地址仅仅只是这个变量存储在内存中的开始地址,从这个地址开始,往后八个内存单元才是这个变量b在内存中的真正所在的位置)。
第二条指令与第一条类似,仅是把起始地址换成了X+08x(变量c在内存中的地址),最后一条指令表示,把寄存器rax中的值写入地址为X+0x10开始的连续八个内存单元。
来根据图片理解一下上述操作:
说明如下:
-
假定寄存器rsp的值是X。
-
图中内存部分,每行有8个内存单元,地址从右向左依次+1,也就是说,如果最右边的内存单元地址为X,那么同行最左内存单元地址为X+7。
-
灰色箭头表示数据流动方向。
-
紫红色数字n表示上述案例中的第n条指令。
内存相关基础汇总:
-
内存中每个字节都有一个地址。
-
任何大于一字节的变量在内存中都是存储在相邻连续几个内存单元中。
-
大端存储模式指数据高字节保存在内存低地址中,低字节保存在内存的高地址。
-
小端存储模式指数据低字节保存在内存高地址中,高字节保存在内存的低地址。
扫码关注公众号,获取更多优质内容。