Untitled
内存指令集 memory instructions
word 单词
表示几个字节的组合,在 lc2k 以及 arm 中,一个 word 通常是 4 个字节 32 位
有些地方写的 double word 就表示 8 字节
注意这里的 word 并不等于 char 之类的字符命令,只是一个长度单位,也可以用于指代长度 4 字节的 int
可寻址性 addressable
lc2k 指令集架构下,word 是可寻址的,也就是说,每个地址会指向内存中某个特定的 word,同时这也要求在 lc2k 的内存中 指令必须每 4 字节对齐一次,或者说PC 等指针在内存中的移动长度单位是 4 字节
移动 1 字节(比如 1 char)是非法的
相比较下, ARM 架构是 byte addressable,即每个地址指向一个字节,每次移动的单位也是1字节,可以逐个遍历一个字符串的每一个 char,更可以遍历每个 int (一次性读取 4 个字节)
LEGv8 内存指令代码
与 lc2k 指令一样,基于 base + displacement 的寻址方式,base为一个寄存器,displacement 为一个9位立即数,范围为 -256 ~ 255, 其寄存器长度为 64 位,因此从内存中读取的 数据会被扩展到 64 位,且需要经过 sign extension
LDUR: Load Register,LDUR X1 [X2, #40]表示X1 = MEM[X2 + 40]一次性读取STUR: Store Register,STUR X1 [X2, #40]表示MEM[X2 + 40] = X1LDURSW: Load Register Signed Word,LDURSW X1 [X2, #40]表示X1 = MEM[X2 + 40]一次性读取,但是会将读取的值扩展为 64 位STURW: Store Register Word,STURW X1 [X2, #40]表示MEM[X2 + 40] = X1但是会截断为 32 位LDURH: Load Register Halfword,LDURH X1 [X2, #40]表示X1 = MEM[X2 + 40]一次性读取,但是会将读取的值扩展为 64 位STURB: Store Register Byte,STURB X1 [X2, #40]表示MEM[X2 + 40] = X1但是会截断为 8 位MOVZ: Move with Zero,MOVZ X1, #10, LSL #2表示X1 = 10 << 2,常用于一个寄存器的初始化,将某几个位置变成指定的 16 位数字,其他位置初始化为 0MOVK: Move with Keep,MOVK X1, #10, LSL #2表示X1 = X1 | 10 << 2,常用于一个寄存器的初始化,将某几个位置变成指定的 16 位数字,其他位置保持不变
命名特点
- ‘SW’ 表示 signed word,有符号的 word
- ‘H’ 表示 halfword,半字,16 位
- ‘UR’ 表示 unsigned register,无符号寄存器
位数扩展
- 有符号数的符号位(most significant number)为 1 时,扩展时高位补 1
- 有符号数的符号位(most significant number) 为 0 时,扩展时高位补 0
- 无符号数的扩展时高位补 0
寄存器知道存储数值是有符号还是无符号的吗
答案是不知道,寄存器只会存储数值,不会存储数值的符号,符号是由汇编码的不同操作指令来决定的,比如 LDURSW 就是有符号数,LDUR 就是无符号数
例子
比如将一般的 int 进行 bit shift, 那么 1 >> 2 = 0, 而 -1 >> 2 = -1
数字存储顺序
Endian 这个词出自Jonathan Swift书写的《格列佛游记》。这本书根据将鸡蛋敲开的方法不同将所有的人分为两类,从圆头开始将鸡蛋敲开的人被归为Big Endian,从尖头开始将鸡蛋敲开的人被归为Littile Endian(这句话最为形象)。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开
大端存储 Big Endian (反)
一个数的最高位字节(最重要的部分,称为 “big end”)被存储在内存的最低地址处
也就是最靠前的位置,例如 0x12345678 在内存中的存储顺序是 12 34 56 78
小端存储 Little Endian (正)
一个数的最低位字节(最不重要的部分,称为 “little end”)被存储在内存的最低地址
也就是最靠前的位置,例如 0x12345678 在内存中的存储顺序是 78 56 34 12
注
- 在字节内的位顺序是不变的,只是字节的顺序发生了变化
- 大端存储更加符合人类的阅读习惯,在网络协议中比较常见
- 小端存储由于符合算术从小位到高位的顺序,因此在PC (x86) 中更加常见
- leg, arm 有两种可能的存储顺序,取决于硬件的设计,但是默认小端存储
内存对齐 memory alignment
对于一个结构体而言,里面有多个 不同数据类型的变量,如 char, short, double, int 等变量这些变量如果直接存储不对齐,那么会导致内存访问效率低下
在后面我们会知道,内存会被分配到固定尺寸的 chunk 里面,每个chunk 一般是 32位,且读取 chunk 的时候是一次性全部读取,所以如果一个变量跨越了两个 chunk,那么就会导致读取两次
对于一个 char 类型的变量,它可以存储在一个 chunk 中任意的位置,因为如果我们要读取之,只需要 ldurb 或者 read 整个 word 然后丢弃其他部分就行
对齐规则
- 每一个变量的开始地址一定能被其尺寸整除
padding表示填充,也就是说如果一个变量的大小不是 4 的倍数,那么就会在其后面填充一些字节,使得下一个变量的地址是 4 的倍数
结构体的特殊对齐规则
即使将一个结构体通过 padding 进行填充使得满足 4字节整除,但是如果前面有别的变量比如 char 使得结构体的开始位置并没有满足 4 字节整除,那么这个结构体的地址就是这个 char 的地址,而不是填充后的地址
