ARM64体系结构编程2-加载与存储指令的变种和mov指令

不同位宽的LDR和STR指令

指令 Describe
LDR 数据加载指令
LDRSW 有符号的数据加载指令,单位:字
LDRB 数据加载指令,单位:字节
LDRSB 有符号的加载指令,单位:字节
LDRH 数据加载指令,单位:半字
LDRSH 有符号的数据加载指令,单位:半字
STRB 数据存储指令,单位:字节
STRH 数据存储指令,单位:半字
1 my_data:
2 	.quad 0x8a
3 ldr x5, =my_data	//使用LDR伪指令加载标签my_data的内存地址
4 ldrb x1, [x5]		//8a 前面进行 零扩展
5 ldrsb x2, [x5]	// 8a 前面进行 有符号扩展
  • 第 4 行使用 LDRB 指令(无符号)读取标签 my_data 内存地址中第 1 字节的数据(0x8a),此时读取的数据为 0x000000000000008A。
  • 第 5 行使用 LDRB 指令(有符号)读取标签 my_data 内存地址中第 1 字节的数据(0x8a),此时读取的数据为 0xFFFFFFFFFFFFFF8A

不可扩展的指令:LDUR 和 STUR

  • 可扩展,使用偏移量按照数据大小来扩展,取值范围是(0~32760),
  • 不可扩展,偏移量只能按照字节来扩展,取值范围(-256~256)。
LDUR Xt, [Xn|SP, #simm]   // 不可拓展的数据加载指令
STUR Xt, [Xn|SP, #simm]   // 不可拓展的数据存储指令

多字节内存指令

LDP Xt1, Xt2, [Xn|SP, #simm]   //出栈

以 Xn/SP 寄存器的值+simm 地址的值作为内存地址,然后将该内存地址的值给 Xt1, 接着读取 Xn/SP 寄存器的值+simm+8(内存对齐)的值给 Xt2.

STP Xt1, Xt2, [Xn|SP, #simm]   //入栈

以 Xn/SP 寄存器的值+simm 地址的值作为内存地址,把 Xt1 寄存器的值存储到这个内存地址中 , 接着将 Xt2 的值存储到 Xn/SP 寄存器的值+simm+8(内存对齐)处。

STP Xt1, Xt2, [Xn|SP, #simm]!   //前变基模式

先计算 Xn寄存器的值=Xn/SP 寄存器的值+simm,然后以新的 Xn 寄存器的值为内存地址,把 X1 寄存器的值存储到这个地址处,再把 X2 寄存器的值存储到这个内存地址+8 处。

LDP Xt1, Xt2, <Xn|SP>, <#imm>  //后变基模式

Xn 寄存器做为基地址,把 [Xn] 的值存到 Xt1 寄存器中,读取 [Xn + 8] 到 Xt2 中。最后,更新 Xn 寄存器的值为 [Xn] + imm,Xn 寄存器可以使用 SP 寄存器。

注意偏移量 simm 必须要满足

  • simm 取值范围为 -512~504
  • simm 必须为 8 的倍数

入栈和出栈

栈通常用来保存以下内容

  • 临时存储的数据,例如局部变量,传递参数等
  • 参数,在函数调用过程,如果传递的参数少于或等于 8 个,那么使用 X0~X7 通过寄存器来传递,当参数多于 8 个,就需要使用栈来传递。

栈从高低地址往低地址生长,数据出栈,SP 增大,数据入栈,SP 减小,栈空间扩大;数据出栈,SP 增大。栈空间减小。

.globalmain
main:
	//栈往下扩展16字节
	stp x29, x30, [sp, #-16]//把栈继续往下扩展8字节(相当于栈帧向下移一位)
	add sp, sp, #-8

	mov x8, #1

	//x8保存到SP指向的位置上
	str x8, [sp]

	//释放刚才扩展的8字节的栈空间(栈帧向上移动一位,将X8的值出栈)
	add sp, sp, #8

	//main函数返回 0
	mov w0, 0

	//恢复x29和x30寄存器的值,使SP指向原位置(将X29和x30出栈)
	ldp x29, x30, [sp], #16
	ret

mov指令

mov <Xd|SP>, <Xn|SP>  //寄存器之间的搬移
mov <Xd>, $imm		  //立即数之间的搬移

你可能感兴趣的:(ARM64,arm,嵌入式硬件,linux,ubuntu)