ARM下位置无关码和位置相关码介绍

由于在学I2C裸板程序中在分析head.S时用到了这个位置无关码这个概念,并且之前一直不明白位置无关码,故此次通过查阅其他大神的博客了解可以得到下面的教程,希望对学ARM的朋友有一点帮助。

参考:http://www.cnblogs.com/mylinux/p/5577472.html

位置无关代码:即该段代码无论放在内存的哪个地址,都能正确运行。究其原因,是因为代码里没有使用绝对地址,都是相对地址。
位置相关码:即它的地址与代码处于的位置相关,是绝对地址,如:mov PC ,#0xff;ldr pc,=0xffff等。

为什么需要位置无关码
通常情况下,将bootloader程序下载到ROM的0x0地址进行启动(比如固化到NorFlash中)。然而在很多的设计中,比如将bootloader固化在NAND中,在系统复位后S3C2440A中NAND控制器自动读取NAND中存储的前4K的代码到s3c2440a中称之为steppingstone(垫脚石)的SRAM中,steppingstone中的代码用进行一些非核心的硬件初始化,再将NAND中剩下的bootloader代码拷贝到SDRAM中运行。一般境况下两者的地址并不相同,程序在SDRAM中的地址重定位过程必须由程序员来完成。这样就有了位置无关代码的概念,指代码不在连接时制定的运行地址空间,也可以执行,它一段加载到任意地址空间都能执行的特殊代码。这样在steppingstone设计的代码要用位置无关设计。一些裸板程序中也可是需要。如果你的这段代码需要实现位置无关,那么你就不能使用绝对寻址指令,否则的话就是位置有关了。

位置无关码的使用场合
1. 程序在运行期间动态加载到内存;
2. 程序在不同场合与不同程序组合后加载到内存(共享的动态链接库);
3. 在运行期间不同地址相互之间的映射(如bootloader)

怎么实现位置无关码?
{

  1. 位置无关的函数跳转

  2. 位置无关的常量访问

}

位置无关的汇编写法
1.B指令
跳转指令,B指令接受一个相对地址,因此在汇编里用B跳转到一个标号时,实际编译的结果是一个相对跳转。相对地址有个范围限制,即目标不能太远,一般目标放在同一个文件里是肯定可以的。 Offset must IN 32Mbit

_start:
    b   Reset
Reset:

2.BL指令
同样也是跳转指令,一般用于跳转函数

 bl  disable_watch_dog

3.ADR指令
获取标号的地址,在编译时会使用PC+偏移的方式得到该位置的地址。例如,当TEXT_BASE是0时
SMRDATA可能被放在0x100的位置,当TEXT_BASE为0x30000000时放在0x30000100的位置。
使用ADR总能获取正确的位置,与程序的加载地址无关

    ADR R0, SMRDATA
SMRDATA:
    .word  0x22111120 
    .word  0x00002F50 
    .word  0x00000700 

4.LDR指令
当加标号时,LDR可以用于伪指令,也可以真指令。
真指令: (标号前不加=号,表示取标号处的值)

    LDR R0,  SDRDATA

实际被编译为LDR R0, [PC, #NN],其中NN是目标的相对距离
伪指令:(标号前加=号,取标号的地址)

    LDR R0, =SDRDATA

实际编译的时候的时候,会在某位置存处SDRDATA的值,然后用一个LDR取出来。

可以看出,使用=和不使用=号是有很大区别的。
无=号:取该标号处的值,位置无关
有=号:取该标号的地址,位置相关

5.bl/b调用的c语言函数里面也不要使用全局变量, 因为c里面的全局变量的地址是根据链接地址生成的
in head.s

Reset:                  
    ldr sp, =4096           @ 设置栈指针,以下都是C函数,调用前需要设好栈
    bl  disable_watch_dog   @ 关闭WATCHDOG,否则CPU会不断重启
    bl  clock_init          @ 设置MPLL,改变FCLK、HCLK、PCLK
    bl  memsetup            @ 设置存储控制器以使用SDRAM
    bl  nand_init           @ 初始化NAND Flash

nand.c :

void nand_init(void)
{
    S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;
    S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;

#define TACLS   0
#define TWRPH0  3
#define TWRPH1  0

    /* 判断是S3C2410还是S3C2440 */
    if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
    {
        /* 使能NAND Flash控制器, 初始化ECC, 禁止片选, 设置时序 */
        s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);

        /* 复位NAND Flash */
        s3c2410_nand_reset();
    }
    else
    {
        /* 设置时序 */
        s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
        /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
        s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);

        /* 复位NAND Flash */
        s3c2440_nand_reset();
    }

一开始程序位于Nand中,在上电时,Nand中的前4k内容会被拷贝到片内内存SRAM中,所以得用位置无关码,调用的c语言函数中不允许有全局变量,故上述代码中没有全局变量。

——作者:Edison Gao(小白要学arm)

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值