天天看點

樹梅派4B(A72)開發記錄2——MOV/LDR/LDR僞指令差別

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