LDR伪指令和MOV机器码分析

1 LDR伪指令对应的汇编指令

我们写在汇编程序中的LDR伪指令并不直接对应具体的机器码,LDR伪指令会由编译器通过一定的技巧(文字池)转化为具体的汇编指令(对应具体的机器码)。

如下以最简单的点亮LED的汇编程序,分析下LDR伪指令对应的汇编指令:

/*
 * 点亮LED1: gpf4
 */

.text
.global _start

_start:

/* 配置GPF4为输出引脚
 * 把0x100写到地址0x56000050
 */
	ldr r1, =0x56000050
	ldr r0, =0x100	/* mov r0, #0x100 */
	str r0, [r1]


/* 设置GPF4输出高电平 
 * 把0写到地址0x56000054
 */
	ldr r1, =0x56000054
	ldr r0, =0	/* mov r0, #0 */
	str r0, [r1]

	/* 死循环 */
halt:
	b halt

简单的makefile文件如下:

all:
	arm-linux-gcc -c -o led_on.o led_on.S
	arm-linux-ld -Ttext 0 led_on.o -o led_on.elf
	arm-linux-objcopy -O binary -S led_on.elf led_on.bin
	arm-linux-objdump -D led_on.elf > led_on.dis
clean:
	rm *.bin *.o *.elf

我们需要分析反汇编码来得到LDR被处理后的汇编指令,arm-linux-objdump -D led_on.elf > led_on.dis就是用来得到反汇编码的。

led_on.dis的内容如下:


led_on.elf:     file format elf32-littlearm

Disassembly of section .text:

00000000 <_start>:
   0:	e59f1014 	ldr	r1, [pc, #20]	; 1c <.text+0x1c>
   4:	e3a00c01 	mov	r0, #256	; 0x100
   8:	e5810000 	str	r0, [r1]
   c:	e59f100c 	ldr	r1, [pc, #12]	; 20 <.text+0x20>
  10:	e3a00000 	mov	r0, #0	; 0x0
  14:	e5810000 	str	r0, [r1]

00000018 <halt>:
  18:	eafffffe 	b	18 <halt>
  1c:	56000050 	undefined
  20:	56000054 	undefined

可以看到ldr r1, =0x56000050对应的汇编指令为ldr r1, [pc, #20] ; 1c <.text+0x1c>,编译器将0x56000050这个值直接放到了代码段中,然后使用ldr指令(注意:这里为ldr指令,而不是伪指令)将对应内存里的值读取到r1中。

这里需要注意下pc的值:
对于ldr r1, [pc, #20],这条指令来说当前执行指令的地址为0,而由于当前ARM7为3级流水线。PC的值等于当前执行指定的地址值加8。所以最终就是去8 + 20 = 0x1c的内存中去取数据。

ARM3级流水线:假设当前执行地址A的指令,已经在对地址A+4的指令进行译码了,在对地址A+8的指令进行取值了。所以当前PC的值为A+8。


2 MOV指令对应的机器码

我们发现ldr r0, =0x100指令直接被替换成了mov r0, #256 ; 0x100,这是因为0x100是可以用立即数表示的,所以这里直接使用了mov指令。我们可以看到mov r0, #256 ; 0x100对应的机器码为e3a00c01,那么mov指令的机器码的格式是什么呢?

LDR伪指令和MOV机器码分析_第1张图片

Rd:为目标寄存器的值。
shifter_operand:这12位代表了立即数A,前4位的值为B,后8的值为C。则A为B循环右移2 * C位。

对于e3a00c01来说,就是0x1循环右移2*0xC = 24位,即最终的结果为0x100。

你可能感兴趣的:(Linux)