对基于ARM的一段汇编代码的解读

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_valldr r2,mem_cfg_valldr 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_valldr r2,mem_cfg_valldr 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的用途?

它的含义就是使得下面的代码按一定规则对齐。

展开阅读全文

没有更多推荐了,返回首页