ARM的step内存到SDRAM内存代码复制程序调试之罪魁祸首 ADR与LDR

本文详细描述了在ARM处理器上,从step内存到SDRAM内存进行代码复制过程中遇到的问题。作者通过逐步排查,发现在初始化SDRAM的代码中,将`ldr r1,=sdram_config`替换为`adr r1,sdram_config`后,程序运行恢复正常。文章探讨了ADR和LDR指令的差异,指出ldr的地址位置无关性可能导致错误,而adr的寻址限制更小但更为安全。最终,作者通过反汇编和二进制比较确认了问题的根源。" 111779464,10293244,LBP特征点检测算法详解,"['特征点检测', 'LBP算法', '图像处理', '纹理分析', '计算机视觉']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

start.S启动的汇编代码
#define S3C2440_MPLL_200MHZ ( (0x5C<<12)|(0x01<<4)|(0x02) )
#define MEM_CTL_BASE   0x48000000

.text
.global _start
_start:

/*1关看门狗*/
 mov r0,#0x53000000
 mov r1,#0
 str r1,[r0]
 
/*2设置时钟*/
 ldr r0,=0x4C000014
 mov r1,#0x03
 str r1,[r0]
 
 mrc  p15,0,r1,c1,c0,0 
 orr  r1,r1,#0xc0000000 
 mcr  p15,0,r1,c1,c0,0

 ldr r0,=0x4C000004
 ldr r1,=S3C2440_MPLL_200MHZ
 str r1,[r0]
/*3初始化SDRAM*/
 mov r0,#MEM_CTL_BASE
 adr r1,sdram_config
 add r3,r0,#(13*4) 
1:
 ldr r2,[r1],#4
 str r2,[r0],#4
 cmp r3,r0
 bne 1b 
/*4重定位:把代码从0内存复制到它的链接地址去*/
 mov r0,#0;
 ldr r1,=0x33f80000
 mov r2,#4096
1: 
 ldr r3,[r0],#4
 str r3,[r1],#4
 cmp r2,r0
 bne 1b
/*清bss段*/

/*5执行main函数*/ 
 ldr sp,=0x34000000
 ldr pc,=main
sdram_config:
    .long 0x22011110
  .long 0x00000700
  .long 0x00000700
  .long 0x00000700
  .long 0x00000700
  .long 0x00000700
  .long 0x00000700
  .long 0x00018005
  .long 0x00018005
  .long 0x008C04F4
  .long 0x000000B1
  .long 0x00000030
  .long 0x00000030

init.c测试文件
#define GPBCON (*(volatile unsigned long *)0x56000010)
#define GPBDAT (*(volatile unsigned long *)0x56000014)


void delay(unsigned long dly)
{
 for(;dly>0;dly--);
}


int  main()
{
 int i=0; 
 GPBCON = 1<<5*2 | 1<<6*2 | 1<<7*2 | 1<<8*2;
 while(1)
 { 
  delay(100000);  
  GPBDAT =(~(i<<5)); 
  ++i;  
  i %= 16; 
 }
 return 0;
}
链接脚本
SECTIONS{
 . = 0x33f80000;
 .text   : {*(.text)}
 
 . = ALIGN(4);
 .rodata : {*(.rodata*)}
 
 . = ALIGN(4);
 .data   : {*(.data)}
 
 . = ALIGN(4);
 __bss_start = .;
 .bss    : {*(.bss) *(COMMON)}
 __bss_end   = .;
}

Makefile
objs := start.o init.o
boot.bin:$(objs)
 arm-linux-ld  -Tboot.lds -o boot_elf $^
 arm-linux-objcopy -O binary boot_elf $@
 arm-linux-objdump -D -m arm boot_elf >boot.dis
%.o : %.S
 arm-linux-gcc  -c -o $@ $<
%.o : %.c
 arm-linux-gcc  -c -o $@ $<
clean:
 rm -f *.bin boot_elf *.o *.dis

调试了一个下午,在这段程序的运行过程中,发现程序总是无法点亮LED,也就是程序根本就没有
运行到main函数中。然后我就从后向前去找程序可能的出错地点。
1,刚开始 我怀疑是ldr pc,=main这句指令没有跳到地方。后来换用bl main。发现还是一样的结
   果。查看反汇编,发现指令也是跳到了指定的位置了。于是,继续向上找。
2,后来觉得是不是/*2设置时钟*/ 这个有问题,于是把这段删除了,然后问题依然没有解决!
3,排除法,问题可能出在/*3初始化SDRAM*/!!!!但是查看反汇编,也没有找到问题的所在!
   最后,通过对比以前写的汇编程序发现,程序的28行(原来写的是ldr r1,=sdram_config)改成
   adr r1,sdram_config后程序正常了!
   后来我在网上搜了下:ldr和adr的区别主要就是地址的位置无关性的差别。ldr伪指令操作,
   一旦实际运行物理地址和期望运行物理地址存在差别,那就会造成程序运行错误。虽然adr有
   这么多优点,但是adr的寻址空间只有前后4kb,而且必须在同一个代码段中,ldr就没有这些
   要求。
   我查看了这分别包含两条指令的程序的反汇编,也没有发现有什么大的分别!
   比较搞笑的是这两都反汇编出的代码是一样的!但是两都的二进制文件却是不一样的
   当使用adr对应的这个二进制指令为: e28f1034
  当使用ldr对应的这个二进制指令为: e59f1074
  这还是后来我写了个文件比较程序才发现的!这两个指令对应的汇编是什么,有待查证!待续。。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值