0.概述:这篇博客写的主要是在阅读一段汇编代码段的过程中发现不明白的地方,以及原因的寻找。
1.完整代码段
1.1汇编代码段。名为:start.S
.equ MEM_CTL_BASE, 0X48000000
.equ SDRAM_BASE, 0X30000000
.text
.global _start
_start:
bl disable_watch_dog
bl memsetup
bl copy_steppingstone_to_sdram
ldr pc,=on_sdram
on_sdram:
ldr sp,=0x32000000
bl main
halt_loop:
b halt_loop
disable_watch_dog:
ldr r1,=0x53000000
mov r2,#0x00
str r2,[r1]
mov pc,lr
copy_steppingstone_to_sdram:
mov r1,#0
ldr r2,=SDRAM_BASE
mov r3,#1024*4
1:
ldr r4,[r1],#4
str r4,[r2],#4
cmp r1,r3
bne 1b
mov pc,lr
memsetup:
mov r1,#MEM_CTL_BASE
adrl r2,mem_cfg_val
add r3,r1,#52
1:
ldr r4,[r2],#4
str r4,[r1],#4
cmp r1,r3
bne 1b
mov pc,lr
.align 4
mem_cfg_val:
.long 0x22011110 @ BWSCON
.long 0x00000700 @ BANKCON0
.long 0x00000700 @ BANKCON1
.long 0x00000700 @ BANKCON2
.long 0x00000700 @ BANKCON3
.long 0x00000700 @ BANKCON4
.long 0x00000700 @ BANKCON5
.long 0x00018005 @ BANKCON6
.long 0x00018005 @ BANKCON7
.long 0x008c07a1 @ REFERSH
.long 0x000000b1 @ BANKSIZE
.long 0x00000030 @ MRSRB6
.long 0x00000030 @ MRSRB7
1.2. C代码段。名为leds.c。
#define GPFCON (*(volatile unsigned long *)0x56000050)
#define GPFDAT (*(volatile unsigned long *)0x56000054)
int main()
{
unsigned int i;
GPFCON |= (1<<8)+(1<<10)+(1<<12);
while(1)
{
for(i=0;i<=10000;i++);
GPFDAT ^= 1<<4;
for(i=0;i<=10000;i++);
GPFDAT ^= 1<<5;
for(i=0;i<=10000;i++);
GPFDAT ^= 1<<6;
}
return 0;
}
1.3. 将链接完毕以后的文件进行反汇编。
sdram_elf: file format elf32-littlearm
Disassembly of section .text:
30000000 <_start>:
30000000: eb000005 bl 3000001c <disable_watch_dog>
30000004: eb000010 bl 3000004c <memsetup>
30000008: eb000007 bl 3000002c <copy_steppingstone_to_sdram>
3000000c: e59ff090 ldr pc, [pc, #144] ; 300000a4 <mem_cfg_val+0x34>
30000010 <on_sdram>:
30000010: e3a0d432 mov sp, #838860800 ; 0x32000000
30000014: eb000025 bl 300000b0 <main>
30000018 <halt_loop>:
30000018: eafffffe b 30000018 <halt_loop>
3000001c <disable_watch_dog>:
3000001c: e3a01453 mov r1, #1392508928 ; 0x53000000
30000020: e3a02000 mov r2, #0
30000024: e5812000 str r2, [r1]
30000028: e1a0f00e mov pc, lr
3000002c <copy_steppingstone_to_sdram>:
3000002c: e3a01000 mov r1, #0
30000030: e3a02203 mov r2, #805306368 ; 0x30000000
30000034: e3a03a01 mov r3, #4096 ; 0x1000
30000038: e4914004 ldr r4, [r1], #4
3000003c: e4824004 str r4, [r2], #4
30000040: e1510003 cmp r1, r3
30000044: 1afffffb bne 30000038 <copy_steppingstone_to_sdram+0xc>
30000048: e1a0f00e mov pc, lr
3000004c <memsetup>:
3000004c: e3a01312 mov r1, #1207959552 ; 0x48000000
30000050: e28f2018 add r2, pc, #24
30000054: e1a00000 nop ; (mov r0, r0)
30000058: e2813034 add r3, r1, #52 ; 0x34
3000005c: e4924004 ldr r4, [r2], #4
30000060: e4814004 str r4, [r1], #4
30000064: e1510003 cmp r1, r3
30000068: 1afffffb bne 3000005c <memsetup+0x10>
3000006c: e1a0f00e mov pc, lr
30000070 <mem_cfg_val>:
30000070: 22011110 andcs r1, r1, #4
30000074: 00000700 andeq r0, r0, r0, lsl #14
30000078: 00000700 andeq r0, r0, r0, lsl #14
3000007c: 00000700 andeq r0, r0, r0, lsl #14
30000080: 00000700 andeq r0, r0, r0, lsl #14
30000084: 00000700 andeq r0, r0, r0, lsl #14
30000088: 00000700 andeq r0, r0, r0, lsl #14
3000008c: 00018005 andeq r8, r1, r5
30000090: 00018005 andeq r8, r1, r5
30000094: 008c07a1 addeq r0, ip, r1, lsr #15
30000098: 000000b1 strheq r0, [r0], -r1
3000009c: 00000030 andeq r0, r0, r0, lsr r0
300000a0: 00000030 andeq r0, r0, r0, lsr r0
300000a4: 30000010 andcc r0, r0, r0, lsl r0
300000a8: e1a00000 nop ; (mov r0, r0)
300000ac: e1a00000 nop ; (mov r0, r0)
300000b0 <main>:
300000b0: e52db004 push {fp} ; (str fp, [sp, #-4]!)
300000b4: e28db000 add fp, sp, #0
300000b8: e24dd00c sub sp, sp, #12
300000bc: e59f30c4 ldr r3, [pc, #196] ; 30000188 <main+0xd8>
300000c0: e59f20c0 ldr r2, [pc, #192] ; 30000188 <main+0xd8>
300000c4: e5922000 ldr r2, [r2]
300000c8: e3822c15 orr r2, r2, #5376 ; 0x1500
300000cc: e5832000 str r2, [r3]
300000d0: e3a03000 mov r3, #0
300000d4: e50b3008 str r3, [fp, #-8]
300000d8: ea000002 b 300000e8 <main+0x38>
300000dc: e51b3008 ldr r3, [fp, #-8]
300000e0: e2833001 add r3, r3, #1
300000e4: e50b3008 str r3, [fp, #-8]
300000e8: e51b2008 ldr r2, [fp, #-8]
300000ec: e59f3098 ldr r3, [pc, #152] ; 3000018c <main+0xdc>
300000f0: e1520003 cmp r2, r3
300000f4: 9afffff8 bls 300000dc <main+0x2c>
300000f8: e59f3090 ldr r3, [pc, #144] ; 30000190 <main+0xe0>
300000fc: e59f208c ldr r2, [pc, #140] ; 30000190 <main+0xe0>
30000100: e5922000 ldr r2, [r2]
30000104: e2222010 eor r2, r2, #16
30000108: e5832000 str r2, [r3]
3000010c: e3a03000 mov r3, #0
30000110: e50b3008 str r3, [fp, #-8]
30000114: ea000002 b 30000124 <main+0x74>
30000118: e51b3008 ldr r3, [fp, #-8]
3000011c: e2833001 add r3, r3, #1
30000120: e50b3008 str r3, [fp, #-8]
30000124: e51b2008 ldr r2, [fp, #-8]
30000128: e59f305c ldr r3, [pc, #92] ; 3000018c <main+0xdc>
3000012c: e1520003 cmp r2, r3
30000130: 9afffff8 bls 30000118 <main+0x68>
30000134: e59f3054 ldr r3, [pc, #84] ; 30000190 <main+0xe0>
30000138: e59f2050 ldr r2, [pc, #80] ; 30000190 <main+0xe0>
3000013c: e5922000 ldr r2, [r2]
30000140: e2222020 eor r2, r2, #32
30000144: e5832000 str r2, [r3]
30000148: e3a03000 mov r3, #0
3000014c: e50b3008 str r3, [fp, #-8]
30000150: ea000002 b 30000160 <main+0xb0>
30000154: e51b3008 ldr r3, [fp, #-8]
30000158: e2833001 add r3, r3, #1
3000015c: e50b3008 str r3, [fp, #-8]
30000160: e51b2008 ldr r2, [fp, #-8]
30000164: e59f3020 ldr r3, [pc, #32] ; 3000018c <main+0xdc>
30000168: e1520003 cmp r2, r3
3000016c: 9afffff8 bls 30000154 <main+0xa4>
30000170: e59f3018 ldr r3, [pc, #24] ; 30000190 <main+0xe0>
30000174: e59f2014 ldr r2, [pc, #20] ; 30000190 <main+0xe0>
30000178: e5922000 ldr r2, [r2]
3000017c: e2222040 eor r2, r2, #64 ; 0x40
30000180: e5832000 str r2, [r3]
30000184: eaffffd1 b 300000d0 <main+0x20>
30000188: 56000050 undefined instruction 0x56000050
3000018c: 00002710 andeq r2, r0, r0, lsl r7
30000190: 56000054 undefined instruction 0x56000054
Disassembly of section .ARM.attributes:
00000000 <.ARM.attributes>:
0: 00002541 andeq r2, r0, r1, asr #10
4: 61656100 cmnvs r5, r0, lsl #2
8: 01006962 tsteq r0, r2, ror #18
c: 0000001b andeq r0, r0, fp, lsl r0
10: 00543405 subseq r3, r4, r5, lsl #8
14: 01080206 tsteq r8, r6, lsl #4
18: 04120109 ldreq r0, [r2], #-265 ; 0x109
1c: 01150114 tsteq r5, r4, lsl r1
20: 01180317 tsteq r8, r7, lsl r3
24: Address 0x00000024 is out of bounds.
Disassembly of section .comment:
00000000 <.comment>:
0: 3a434347 bcc 10d0d24 <SDRAM_BASE-0x2ef2f2dc>
4: 74632820 strbtvc r2, [r3], #-2080 ; 0x820
8: 312d676e teqcc sp, lr, ror #14
c: 312e362e teqcc lr, lr, lsr #12
10: 2e342029 cdpcs 0, 3, cr2, cr4, cr9, {1}
14: 00332e34 eorseq r2, r3, r4, lsr lr
在这段汇编代码段中,主要有下面这几个方面的问题困扰这我:
- 在memset代码段,分别使用
adrl r2,mem_cfg_val
、ldr r2,mem_cfg_val
和ldr r2,=mem_cfg_val
会带来哪些区别? - 在诸如disable_watch_dog等代码段的最后,不用
mov pc,lr
会带来什么问题吗? bne 1b
的作用?.align 4
的用途?- // 在mem_cfg_val代码段中对每个寄存器配置的作用?
2.对问题答案的寻找
2.1.adrl与ldr
在memset代码段,分别使用
adrl r2,mem_cfg_val
、ldr r2,mem_cfg_val
和ldr r2,=mem_cfg_val
会带来哪些区别?
首先是对adrl;ldr的用法的简单了解。
2.1.1.adrl和ldr的用法
1.adrl的用法:这里有一个链接。里面讲了adrl,ldr的一些概念。主要有:
- ADR/ADRL是地址读取的伪指令;LDR既可以作为伪指令也能作为加载指令;
- ADR:小范围的地址读取。语法格式:
ADR{cond} register, expr
- ADRL:中等范围的地址读取。语法格式:
ADRL{cond} register, expr
- LDR:
- 伪指令:
LDR register,=expr
。将expr的值赋给寄存器register。 - 加载指令:
LDR register,expr
,在存储器中取出地址为expr的值,存放到寄存器中。
- 伪指令:
2.1.2.在汇编程序中的区别。
下面分别贴出三者反汇编后的代码。
1.adrl r2,mem_cfg_val
:
30000050: e28f2018 add r2, pc, #24
30000054: e1a00000 nop ; (mov r0, r0)
2.ldr r2,mem_cfg_val
:
30000050: e59f2018 ldr r2, [pc, #24] ; 30000070 <mem_cfg_val>
3.ldr r2,=mem_cfg_val
:
30000050: e59f2050 ldr r2, [pc, #80] ; 300000a8 <mem_cfg_val+0x38>
对于第一种;首先要明确的是:adr r2,mem_cfg_val,r2就是mem_cfg_val对应指令当前的地址。其中,“当前 ”—是以运行时的PC为参照。也就是说:通过伪指令adrl最后转化得到的指令是一条基于当前PC的相对偏移地址指令。会将基于PC 相对偏移的地址值读取到寄存器中。从最后的结果可以看出,在执行该命令时,mem_cfg_val代码段在高于当前PC值24的地方。
对于第二种;ldr r2,mem_cfg_val
是将mem_cfg_val对应的地址中存放的数据提取到寄存器r2中。这篇博客的例子中,mem_cfg_val对应的代码段为
30000070 <mem_cfg_val>:
30000070: 22011110 andcs r1, r1, #4
所以可以看出来,在地址为30000070的地方存放的是22011110。那么,在第二种情况下,最后r2中存放的数值就为22011110。
对于第三种;ldr r2,=mem_cfg_val
。首先,mem_cfg_val的地址为30000070。超过了MOV指令的长度范围。所以在这里,汇编时采用的策略为:1.先将30000070存放在存储器的某一个地址中,然后用ldr命令,从该地址块中读取数据到寄存器中,完成对ldr伪指令的实现。
从本例来看,最后系统是将30000070存放在了300000a8中。然后系统再将300000a8中存放的值读到寄存器r2中。所以最后r2中存放的是绝对地址30000070。和当前的PC值没有关。也就是说,用这种方法实际上是绝对寻址的一种。
另外可以参考:ldr 和adr区别在哪里 和 为什么adrl r2,mem_cfg_val这里不用ldr r2,=mem_cfg_val以及ARM立即数,LDR和MOV的区别。
2.1.3.三者比较
首先,结论是:只有第一种方法得到了预期的结果,而第2,3种,都能最终生成bin文件,但是烧到ARM中执行时,都无法得到预期的结果。其原因如下:
对于第二种情况,错误的原因很明显,因为实际第二条指令实现的取出指定地址中存放的数据放到寄存器中。而我们想要的是将这个指定地址存放到寄存器中。
而对于第三种情况,由于这段汇编代码在分别执行到这我们讨论的命令时,对应的SDRAM还没有完成初始化。也就是说,在执行到这里时,SDRAM中还没有存放mem_cfg_var的数据,而只有一些未知的数据。而第三种情况又是采用的绝对寻址的方式。所以这时,将30000070放到寄存器后,在后续取值的时候就会出错。
2.2.在诸如disable_watch_dog等代码段的最后,不用mov pc,lr会带来什么问题吗?
先区分一下B和BL汇编指令。
2.2.1.B与BL指令
- B:B指令无法实现子程序的返回,只能实现单纯的跳转。而且B跳转指令是代码位置无关的。
BL:BL指令在转移到子程序执行之前,将其下一条指令的地址拷贝到R14(LR,链接寄存器)。由于BL指令保存了下条指令的地址,因此使用指令“MOV PC ,LR”即可实现子程序的返回。
参考:arm B和BL指令浅析以及ARM的B,BL跳转指令。2.2.2.关于mov pc,lr的删减
在对本例的实验中总共出现了3处;其中前两处可删可不删。最后一处不能删。具体原因未做深究。不过,在使用
bl
命令进行跳转了以后,如果还需要从子程序中回来,一般最好还是加上mov pc lr
。
2.3.bne 1b
的作用?
bne 1b什么意思呢?一开始老是在找1b的标号处,找了些许时间也没有发现哪里有这个标号。
后来查找相关资料发现,原来0~9的数字为局部标签。局部标签可以重复使用,语法为:
xf:往前跳的意思,就是还未执行的程序,x代表0~9的某个标签,f代表forward的意思。
xb:往后跳的意思,回到原来已经执行过的语句,x达标0~9的某个标签,b代表backward的意思。
可以直接参考汇编中的标号1: 以及bne 1b解释。
2.4..align 4
的用途?
它的含义就是使得下面的代码按一定规则对齐。