openjdk底层(hotspot)汇编指令调用(五)——内存访问
根据前面关于aarch64架构下的编码解释可知,在src\hotspot\cpu\架构
文件夹下,
assembler_xx.hpp
assembler_xx.cpp
register_xx.hpp
register_xx.cpp
register_definitions_xx.cpp
这些文件是有关寄存器定义以及汇编编码函数实现的文件。
对于前述的openjdk底层汇编指令调用,我们只涉及了单纯寄存器调用,对于计算机而言,还有一种调用方式是寄存器和内存之间的互相访问。即,数据从内存到寄存器,或者寄存器到内存
x86的访存模型
这里不再使用aarch64
讲述访存,因为该方式下的访存模型比较复杂,有兴趣的朋友可以访问我以前有关AArch64指令的翻译 AArch64教程_阿达King哥的博客-CSDN博客 。
相比而言,x86
的访存理解起来简单得多。回到x86
架构下的内存访问方式,
下面以具体的例子说明上述表格的内容
假设rbp
寄存器内保存的值是内存中的某个地址,且x86
指令采用AT&T格式,即
opcode src, dst
opcode
为操作码,src
为源,dst
为目的
movl %rdi, (%rbp) //将rdi寄存器中的值放入rbp寄存器所值的内存地址中
这里的括号表示访问的是内存,而不是寄存器本身。当然,可以直接把括号内的名称直接换成内存地址
movl %rdi, (0x55)
可以加上偏移
movl %rdi, -4(%rbp) // 寄存器 -> 内存
movl -8(%rbp), %rsi // 内存 <- 寄存器
这里表示将rdi
寄存器中的值放入指定的内存地址中,该地址为(rbp
内的值减去4)
除此之外,还有一种方式为
mov %rax, (%rbx,%rcx) //R[rax] -> M(R[rbx] + R[rcx])
上述指令的意思是将rax
的值放入指定内存地址中,该地址是M(R[rbx] + R[rcx])
也可以结合偏移
mov %rax, -4(%rbx,%rcx) //R[rax] -> M(R[rbx] + R[rcx]-4)
最后一种方式是乘以系数的方式
mov %rax, (%rbx,%rcx,8) //R[rax] -> M(R[rbx] + R[rcx]*8 )
mov %rax, -4(%rbx,%rcx,8) //R[rax] -> M(R[rbx] + R[rcx]*8 -4)
可以发现如果以最后一条指令说明,我们可以将访存格式的各个部分进行如下定义
mov Ra, Imm(Rb,Ri,S)
其中,Rb
部分被称为基地址(base),Ri
部分被称为变址或索引(index), S
部分被称为比例因子(scale),其中比例因子被强制规定只可使用1,2,4,8
hotspot的x86访存模型
结合上述指令特点,在x86
文件夹的assembler_x86.hpp
文件中定义了Address
类,该类用于物理内存访问时调用。
对照原始的汇编指令,我们可以看出Address
类的各个属性都对应着操作数中的相应部分。以下面的例子说明
mov %eax, -4(%ebx,%ecx,8)
Address类属性 | 汇编 |
---|---|
_base | rbx |
_index | rcx |
_scale | 8 |
_disp | -4 |
hotspot访存指令编码
在assembler_x86.hpp
中定义上述指令
void movl(Address dst, Register src);
该函数的实现如下
void Assembler::movl(Register dst, Address src) {InstructionMark im(this);prefix(src, dst);emit_int8((unsigned char)0x8B);emit_operand(dst, src);
}
实现中将参数进行x86
编码 并发送到内存。