树梅派4B(A72)开发记录2——MOV/LDR/LDR伪指令区别

本文详细解析了ARM指令集中的mov指令用于寄存器和立即数操作,以及ldr指令的寻址模式、变基模式和PC相对地址模式。重点讲解了ldr伪指令的编译原理和实际应用实例,适合了解处理器内核通信的开发者阅读。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.mov指令

mov指令主要用于寄存器之间搬移,也可用于立即数搬移到寄存器;

将立即数搬移到寄存器只有如下两种情况:

(1)16位立即数

(2)16位立即数左移16位/32位/48位后的立即数

2.ldr指令

(1) 基于基地址的寻址模式

基地址保存在寄存器中,常用的指令格式如下:

ldr reg1, [reg2]

(2)变基模式

在基于基地址的寻址模式之上,可以修改reg2中的地址值,常用的指令格式如下:

ldr reg1, [reg2, #8]!   #前变基模式
ldr  reg1,  [reg2], #8  #后变基模式

(3)PC相对地址模式

将pc+offset对应地址处的值加载到寄存器中:

ldr reg0, offset(一个立即数)

立即数的值要在0~32KB之间。

源代码:

.global ldr_test
ldr_test:
	// lab1. 测试ldr地址偏移模式
	mov x1, 0x80000
	mov x3, 16

	/* 读取0x80000地址的值到x0寄存器*/
	ldr x0, [x1]

	ldr x7, 0x20

	/* 读取0x80008地址的值*/
	ldr x2, [x1, #8]

	/* 读取x1+x3 地址的值*/
	ldr x4, [x1, x3]

	/* 读取(x1+ x3<<3) 地址的值*/
	ldr x5, [x1, x3, lsl #3]

	// lab2:观察ldr前変基模式和后变基模式
	/* 前变基模式*/
	ldr x6, [x1, #8]!

	/* 后变基模式 */
	ldr x7, [x1], #8

	//lab3: 观察前变基和后变基的str指令

	/* 观测前变基的str,观察x2的值,地址0x400000的值 */
	mov x2, 0x400000
	ldr x6, =0x1234abce
	str x6, [x2, #8]! 

	/* 观测后变基的str,观察x2的值,地址0x500000的值 */
	mov x2, 0x500000
	str x6, [x2], #8


	ret

反汇编:

(gdb) disassemble 
Dump of assembler code for function ldr_test:
   0x00000000000802b0 <+0>:	mov	x1, #0x80000               	// #524288
   0x00000000000802b4 <+4>:	mov	x3, #0x10                  	// #16
   0x00000000000802b8 <+8>:	ldr	x0, [x1]
   0x00000000000802bc <+12>:	ldr	x7, 0x802dc <ldr_test+44>
=> 0x00000000000802c0 <+16>:	ldr	x2, [x1, #8]
   0x00000000000802c4 <+20>:	ldr	x4, [x1, x3]
   0x00000000000802c8 <+24>:	ldr	x5, [x1, x3, lsl #3]
   0x00000000000802cc <+28>:	ldr	x6, [x1, #8]!
   0x00000000000802d0 <+32>:	ldr	x7, [x1], #8
   0x00000000000802d4 <+36>:	mov	x2, #0x400000              	// #4194304
   0x00000000000802d8 <+40>:	ldr	x6, 0x802f0 <ldr_test+64>
   0x00000000000802dc <+44>:	str	x6, [x2, #8]!
   0x00000000000802e0 <+48>:	mov	x2, #0x500000              	// #5242880
   0x00000000000802e4 <+52>:	str	x6, [x2], #8
   0x00000000000802e8 <+56>:	ret
   0x00000000000802ec <+60>:	.inst	0x00000000 ; undefined
   0x00000000000802f0 <+64>:	and	w14, w30, #0xf07ff07f
   0x00000000000802f4 <+68>:	.inst	0x00000000 ; undefined
End of assembler dump.

显然, ldr x7, 0x20指令被编译器替换成了ldr    x7, 0x802dc <ldr_test+44>,该条指令对应的pc值是0x00000000000802bc,正好满足0x802dc = pc+0x20。

验证:

(gdb) info registers x7
x7             0xd2a00a02f8008c46  -3269602321603982266

(gdb) x/zg 0x00000000000802dc
0x802dc <ldr_test+44>:    0xd2a00a02f8008c46

可见,内存内容和加载到寄存器中的内容一样。

3.ldr伪指令

会被编译器编译为其他指令来实现功能。

.global ldr_test
ldr_test:
	// lab1. 测试ldr地址偏移模式
	mov x1, 0x80000
	mov x3, 16

	/* 读取0x80000地址的值到x0寄存器*/
	ldr x0, [x1]

	/* 读取0x80008地址的值*/
	ldr x2, [x1, #8]

	/* 读取x1+x3 地址的值*/
	ldr x4, [x1, x3]

	/* 读取(x1+ x3<<3) 地址的值*/
	ldr x5, [x1, x3, lsl #3]

	// lab2:观察ldr前変基模式和后变基模式
	/* 前变基模式*/
	ldr x6, [x1, #8]!

	/* 后变基模式 */
	ldr x7, [x1], #8

	//lab3: 观察前变基和后变基的str指令

	/* 观测前变基的str,观察x2的值,地址0x400000的值 */
	mov x2, 0x400000
	ldr x6, =0x1234abce
	str x6, [x2, #8]! 

	/* 观测后变基的str,观察x2的值,地址0x500000的值 */
	mov x2, 0x500000
	str x6, [x2], #8

	ret

关注ldr x6, =0x1234abce这条伪指令。

反汇编:

(gdb) disassemble 
Dump of assembler code for function ldr_test:
   0x00000000000802b0 <+0>:	mov	x1, #0x80000               	// #524288
   0x00000000000802b4 <+4>:	mov	x3, #0x10                  	// #16
   0x00000000000802b8 <+8>:	ldr	x0, [x1]
   0x00000000000802bc <+12>:	ldr	x2, [x1, #8]
   0x00000000000802c0 <+16>:	ldr	x4, [x1, x3]
   0x00000000000802c4 <+20>:	ldr	x5, [x1, x3, lsl #3]
   0x00000000000802c8 <+24>:	ldr	x6, [x1, #8]!
   0x00000000000802cc <+28>:	ldr	x7, [x1], #8
   0x00000000000802d0 <+32>:	mov	x2, #0x400000              	// #4194304
   0x00000000000802d4 <+36>:	ldr	x6, 0x802e8 <ldr_test+56>
   0x00000000000802d8 <+40>:	str	x6, [x2, #8]!
=> 0x00000000000802dc <+44>:	mov	x2, #0x500000              	// #5242880
   0x00000000000802e0 <+48>:	str	x6, [x2], #8
   0x00000000000802e4 <+52>:	ret
   0x00000000000802e8 <+56>:	and	w14, w30, #0xf07ff07f
   0x00000000000802ec <+60>:	.inst	0x00000000 ; undefined

可见0x1234abce被编译器放在了0x802e8这个地址处,这个值又被反汇编器解释成了:and    w14, w30, #0xf07ff07f,至于为什么是这条指令我们暂且不管,这里我们只关注0x1234abce这个值。

验证:

(gdb) x/zg ldr_test+56
0x802e8 <ldr_test+56>:    0x000000001234abce

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

denglin12315

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值