使用ldr命令注意事项

今天犯了一个小错误,调试了几个小时;最后重新分析了几遍反汇编才发现。万丈高楼平地起、勿以浮沙驻高台。


错误代码:

.text
.global _start
_start:
    b reset
    ldr pc,=und_addr
    ldr pc,=swi_addr

und_addr:
    .word undef

swi_addr:
    .word swi_handle

undef:

    ldr sp,=0x32000000 //处理异常调用C函数,设置und模式下的栈,以前是usr模式
    //保存现场
    stmdb sp!,{r0-r12,lr}
    bl print2
    //处理异常
    mrs r0,cpsr //und模式下的cpsr寄存器,也可以改为输出spsr5位和usr模式的cpsr相同
    ldr r1,=und_string
    bl printException
    //恢复现场
    ldmia sp!,{r0-r12,pc}^

und_string:
    .string "undefined instruction exception"

.align 4


swi_handle: 
    ldr sp,=0x33000000 //处理异常调用C函数,设置svc模式下的栈,以前是usr模式
    //保存现场
    stmdb sp!,{r0-r12,lr}
    //处理异常
    mrs r0,cpsr //und模式下的cpsr寄存器,也可以改为输出spsr5位和svc模式的cpsr相同
    ldr r1,=swi_string
    bl printException
    //恢复现场
    ldmia sp!,{r0-r12,pc}^

swi_string:
    .string "swi exception"

.align 4    

reset:
//关看门狗
    ldr r1,=0x53000000
    ldr r0,=0
    str r0,[r1]

//设置时钟
    //① 设置锁定时间LOCKTIME
    ldr r1,=0x4C000000
    ldr r0,=0xFFFFFFFF
    str r0,[r1]

    //② 设置分频系数,使得FCLK:HCLK:PCLK = 8:4:1
    ldr r1,=0x4C000014
    ldr r0,=0x5
    str r0,[r1]

    //③ 根据2440规则,由于②中HDIVN!=0 -> CPU总线模式从快速总线模式到异步模式
    mrc p15,0,r0,c1,c0,0
    orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA
    mcr p15,0,r0,c1,c0,0

    //④ 设置PLL,设置完PLL后,PLL开始工作,锁定时间内CPU停止工作
    /* 设置FCLK = 400MHZ,HCLK = 100MHZ, PCLK = 100MHZ 
     * Mpll(FCLK) = (2*m * Fin) / (p * 2^s)
     * m = M(MDIV) (the value for divider M)+ 8,
     * p = P(PDIV) (the value for divider P) + 2, s = SDIV
     * MDIV = 92(0x5c), PDIV = 1 , SDIV = 1 
     * FCLK = (2*100*12MHZ) / (3*2^1) = 400MHZ */
     ldr r1,=0x4C000004
     ldr r0,= ((92<<12) | (1<<4) | (1<<0))
     str r0,[r1]

//判断启动方式
    mov r1,#0 // r1 = 0;
    ldr r0,[r1] // r0 = [0];将0地址的值备份
    str r1,[r1] // 将0写入0地址
    ldr r2,[r1] // 再将0地址的值读出来给r2
    cmp r1,r2   // 比较r1r2,即比较0地址原来的值和写入的值
    ldr sp,= 0x40000000 + 4096 // 先假设为nor启动
    ldreq sp,= 4096 //如果r1==r2,假设不成立为Nand启动
    streq r0,[r1]   // 还原0地址以前的值

    bl sdram_init
    //bl sdram_init2 //用到有初始值的数组,不是位置无关码    
    bl copy2sdram   
    bl clean_bss

    //从复位后的SVC模式切换到USR模式
    //M[4:0] SVC:10011 USR:10000 
    mrs r0,cpsr
    bic r0,r0,#0xf //修改低四位,进入usr模式
    msr cpsr,r0

    //设置usr模式下的栈,sp_usr
    ldr sp,=0x34000000;


    ldr pc,=sdram_next
sdram_next:     
    bl uart0_init
    mrs r0,cpsr  //SVC模式下的cpsr寄存器
    bl print1

    bl print2

    swi 0x1  /* 执行此命令, 触发SWI异常, 进入0x8执行 */

und_code:
    .word 0xeeadc0de  /* 未定义指令 */

    bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */
    //ldr pc, =main  /* 绝对跳转, 跳到SDRAM */

halt:
    b halt

结果:

使用ldr命令注意事项_第1张图片

分析:

sdram.elf:     file format elf32-littlearm

Disassembly of section .text:

30000000 <_start>:
30000000:   ea00001e    b   30000080 
30000004:   e59ff110    ldr pc, [pc, #272]  ; 3000011c <.text+0x11c>
30000008:   e59ff110    ldr pc, [pc, #272]  ; 30000120 <.text+0x120>

3000000c :
3000000c:   30000014    andcc   r0, r0, r4, lsl r0

30000010 :
30000010:   30000050    andcc   r0, r0, r0, asr r0
*************************************************
3000011c:   3000000c    andcc   r0, r0, ip
30000120:   30000010    andcc   r0, r0, r0, lsl r0
*************************************************
30000014 :
30000014:   e3a0d432    mov sp, #838860800  ; 0x32000000
30000018:   e92d5fff    stmdb   sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}
3000001c:   eb000103    bl  30000430 
30000020:   e10f0000    mrs r0, CPSR
30000024:   e59f10f8    ldr r1, [pc, #248]  ; 30000124 <.text+0x124>
30000028:   eb000216    bl  30000888 
3000002c:   e8fd9fff    ldmia   sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, pc}^

30000030 :
30000030:   65646e75    strvsb  r6, [r4, #-3701]!
........

发生异常的时候,异常向量表中pc没有跳转到相应的执行函数地址,因为我采用了间接的赋值。两次异常都是跳转到und_addr或者swi_addr开始往后面执行,所以两次都执行了undef处理函数。

更正测试:

①直接赋值到对应执行函数处

.text
.global _start
_start:
    b reset
    ldr pc,=undef
    ldr pc,=swi_handle

反汇编:

sdram.elf:     file format elf32-littlearm

Disassembly of section .text:

***************************************
3000011c:   30000014    andcc   r0, r0, r4, lsl r0
30000120:   30000050    andcc   r0, r0, r0, asr r0
***************************************

30000000 <_start>:
30000000:   ea00001e    b   30000080 
30000004:   e59ff110    ldr pc, [pc, #272]  ; 3000011c <.text+0x11c>
30000008:   e59ff110    ldr pc, [pc, #272]  ; 30000120 <.text+0x120>

3000000c :
3000000c:   30000014    andcc   r0, r0, r4, lsl r0

30000010 :
30000010:   30000050    andcc   r0, r0, r0, asr r0

30000014 :
30000014:   e3a0d432    mov sp, #838860800  ; 0x32000000
30000018:   e92d5fff    stmdb   sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}
3000001c:   eb000103    bl  30000430 
30000020:   e10f0000    mrs r0, CPSR
30000024:   e59f10f8    ldr r1, [pc, #248]  ; 30000124 <.text+0x124>
30000028:   eb000216    bl  30000888 
3000002c:   e8fd9fff    ldmia   sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, pc}^

30000030 :
...
30000050 :
30000050:   e3a0d433    mov sp, #855638016  ; 0x33000000
...

结果:
使用ldr命令注意事项_第2张图片


② 间接赋值

.text
.global _start
_start:
    b reset
    ldr pc,und_addr
    ldr pc,swi_addr

反汇编:

sdram.elf:     file format elf32-littlearm

Disassembly of section .text:

30000000 <_start>:
30000000:   ea00001e    b   30000080 
30000004:   e59ff110    ldr pc, [pc, #272]  ; 3000011c <.text+0x11c>
30000008:   e59ff110    ldr pc, [pc, #272]  ; 30000120 <.text+0x120>
*********************
3000011c:   30000014    andcc   r0, r0, r4, lsl r0
30000120:   30000050    andcc   r0, r0, r0, asr r0
*********************

3000000c :
3000000c:   30000014    andcc   r0, r0, r4, lsl r0

30000010 :
30000010:   30000050    andcc   r0, r0, r0, asr r0

30000014 :
30000014:   e3a0d432    mov sp, #838860800  ; 0x32000000
30000018:   e92d5fff    stmdb   sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}
3000001c:   eb000103    bl  30000430 
30000020:   e10f0000    mrs r0, CPSR
30000024:   e59f10f8    ldr r1, [pc, #248]  ; 30000124 <.text+0x124>
30000028:   eb000216    bl  30000888 
3000002c:   e8fd9fff    ldmia   sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, pc}^

30000030 :
...

30000050 :
30000050:   e3a0d433    mov sp, #855638016  ; 0x33000000
...

结果:
使用ldr命令注意事项_第3张图片


总结:

注意ldr pc,=czgldr pc,czg 用法:
ldr pc,=czg =》 pc = czg (就是czg标号的地址)
ldr pc,czg =》 pc = *(czg) (czg标号地址中放的值)

你可能感兴趣的:(【Experience,combined】)