位置无关可执行文件PIE包括位置无关代码PIC和位置无关数据PID两部分。
通常情况下,将bootloader程序下载到ROM的0x0地址进行启动(比如固化到NorFlash中)。然而在很多的设计中,比如将bootloader固化在NAND中,在系统复位后S3C2440A中NAND控制器自动读取NAND中存储的前4K的代码到s3c2440a中称之为
steppingstone的RAM中,steppingstone中的代码用进行一些非核心的硬件初始化,再将NAND中剩下的bootloader代码拷贝到RAM中运行。一般境况下两者的地址并不相同,程序在SDRAM中的地址重定位过程必须由程序员来完成。这样就有了位置无关代码的概念,指代码不在连接时制定的运行地址空间,也可以执行,它一段加载到任意地址空间都能执行的特殊代码。这样在steppingstone设计的代码要用位置无关设计。 位置无关代码可以用于以下场合:
1. 程序在运行期间动态加载到内存;
2. 程序在不同场合与不同程序组合后加载到内存(共享的动态链接库); 3. 在运行期间不同地址相互之间的映射(如bootloader)
ARM位置无关程序设计要点
PID 主要针对可读写数据段(.data 段),其中保存已赋初值的全局变量。为实现其位置无关性,通常使用寄存器R9作为静态基址寄存器,使其指向该可读写段的首地址,并使用相对于基址寄存器的偏移量来对该段的变量进行寻址。这种方法常用于为可重入程序的多个实例产生多个独立的数据段。在程序设计中,一般不必考虑可读写段的位置无关性,这主要是因为可读写数据主要分配在SDRAM 中。
PIC包括程序中的代码和只读数据(.text段),为了保证程序能在ROM和SDRAM空间中能真确的运行,必须采用位置无关代码程序设计。PIC 遵循只读段位置无关ROPI(Read-Only PositionIndependence)的ATPCS(ARM2Thumb Procedure Call Standard)的程序设计规范:
1. 程序设计规范
引用同一ROPI 段或相对位置固定的另一ROPI 段中的符号时,必须是基于PC 的符号引用,即使用相对于当前PC 的偏移量来实现跳转或进行常量访问。
? 位置无关的程序跳转。
在ARM 汇编程序中,使用相对跳转指令B/BL 实现程序跳转。指令中所跳转的目标地址用基于当前PC 的偏移量来表示,与链接时分配给地址标号的绝对地址值无关,因而代码可以在任何位置进行跳转,实现位置无关性。
另外,还可使用ADR 或ADRL 伪指令将地址标号值读取到PC 中实现程序跳转。这是因为ADR或ADRL等伪指令会被编译器替换为对基于PC 的地址值进行操作,但这种方式所能读取的地址范围较小,并且会因地址值是否为字对齐而异。
但在ARM 程序中,使用LDR 等指令直接将地址标号值读取到PC 中实现程序跳转不是位置无关的。 例如:
LDR PC , = main 上面的LDR 汇编伪指令编译后的结果为: LDR PC , [ PC , OFFSET_ TO_L POOL ] ... LPOOL DCD main 可见, 虽然LDR 是把基于PC 的一个存储单元LPOOL 的内容加载到PC 中,但该存储单元中保存的却是链接时所决定的main 函数入口的绝对地址,所以main函数实际所在的段不是位置无关。
? 位置无关常量访问
在应用程序中,经常要读写相关寄存器以完成必要的硬件初始化。为增强程序的可读性,利用EQU 伪指令对一些常量进行赋值,但在访问过程中, 必须实现位置无关性。下面以 U-boot的
SDRAM初始化介绍位置无关的常量访问方法。
#define BWSCON 0x48000000 /* BWSCON */ #define DW8 (0x0) #define DW16 (0x1) #define DW32 (0x2) ... _TEXT_BASE: .word TEXT_BASE .globl lowlevel_init lowlevel_init: /* memory control configuration */ /* make r0 relative the current location so that it */ /* reads SMRDATA out of FLASH rather than memory ! */ ldr r0, =SMRDATA ldr r1, _TEXT_BASE sub r0, r0, r1 ldr r1, =BWSCON /* Bus Width Status Controller */ add r2, r0, #13*4 0: ldr r3, [r0], #4 str r3, [r1], #4 cmp r2, r0 bne 0b /* everything is fine now */ mov pc, lr .ltorg /* the literal pools origin */ ... .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT) .word 0x32 .word 0x30 .word 0x30 汇编反汇编后 lowlevel_init.o: file format elf32-littlearm Disassembly of section .text: 00000000 <_TEXT_BASE>: 0: 00000000 andeq r0, r0, r0 00000004