网站开发的后台开发工具,餐饮商城网站建设,邯郸市建设局,网页游戏平台制作ARM的位置无关程序设计 ARM处理器支持位置无关的程序设计#xff0c;这种程序加载到存储器的任意地址空间都可以正常运行#xff0c;其设计方法在嵌入式应用系统开发中具有重要的作用。尤其在裸机状态下开发Bootloader程序及进行内核初始化设计#xff1b;利用位置无关的程序…ARM的位置无关程序设计 ARM处理器支持位置无关的程序设计这种程序加载到存储器的任意地址空间都可以正常运行其设计方法在嵌入式应用系统开发中具有重要的作用。尤其在裸机状态下开发Bootloader程序及进行内核初始化设计利用位置无关的程序设计方法还可以在具体应用中用于构建高效率动态链接库因而了解位置无关的程序设计方法有助于开发人员设计出结构简单、清晰的应用程序。 应用程序必须经过编译、汇编和链接后才变成可执行文件在链接时要对所有目标文件进行重定位(relocation)建立符号引用规则同时为变量、函数等分配运行地址。当程序执行时系统必须把代码加载到链接时所指定的地址空间以保证程序在执行过程中对变量、函数等符号的正确引用使程序正常运行。在具有操作系统的系统中重定位过程由操作系统自动完成。 在设计Bootloader程序时必须在裸机环境中进行这时Bootloader映像文件的运行地址必须由程序员设定。通常情况下将Bootloader程序下载到ROM的0x0地址进行启动而在大多数应用系统中为了快速启动首先将Bootloader程序拷贝到SDRAM中再运行。一般情况下这两者的地址并不相同程序在SDRAM中的地址重定位过程必须由程序员完成。实际上由于Bootloader是系统上电后要执行的第一段程序Bootloader程序的拷贝和在这之前的所有工作都必须由其自身来完成而这些指令都是在ROM中执行的。也就是说这些代码即使不在链接时所指定的运行时地址空间也可以正确执行。这就是位置无关代码它是一段加载到任意地址空间都能正常执行的特殊代码。
位置无关代码常用于以下场合 程序在运行期间动态加载到内存 程序在不同场合与不同程序组合后加载到内存(如共享的动态链接库) 在运行期间不同地址相互之间的映射如Bootloader程序。 虽然在用GCC编译时使用-fPIC选项可为C语言产生位置无关代码但这并不能修正程序设计中固有的位置相关性缺陷。特别是汇编语言代码必须由程序员遵循一定的程序设计准则才能保证程序的位置无关性。
ARM程序的位置无关可执行文件PIEPositionIndependentExecutable包括位置无关代码PIC和位置无关数据PIDPositionIndependent Data两部分。 PID主要针对可读写数据段.data段其中保存已赋初值的全局变量。为实现其位置无关性通常使用寄存器R9作为静态基址寄存器使其指向该可读写段的首地址并使用相对于基址寄存器的偏移量来对该段的变量进行寻址。这种方法常用于为可重入程序的多个实例产生多个独立的数据段。在程序设计中一般不必考虑可读写段的位置无关性这主要是因为可读写数据主要分配在SDRAM中。 PIC包括程序中的代码和只读数据.text段为保证程序能在ROM和SDRAM空间都能正确运行如裸机状态下的Bootloader程序必须采用位置无关代码程序设计。
PIC遵循只读段位置无关ROPIReadOnlyPosition Independence的ATPCSARMThumb Procedure Call Standard的程序设计规范
1 程序设计规范1
引用同一ROPI段或相对位置固定的另一ROPI段中的符号时必须是基于PC的符号引用即使用相对于当前PC的偏移量来实现跳转或进行常量访问。
① 位置无关的程序跳转。在ARM汇编程序中使用相对跳转指令B/BL实现程序跳转。指令中所跳转的目标地址用基于当前PC的偏移量来表示与链接时分配给地址标号的绝对地址值无关因而代码可以在任何位置进行跳转实现位置无关性。
另外还可使用ADR或ADRL伪指令将地址标号值读取到PC中实现程序跳转。这是因为ADR或ADRL等伪指令会被编译器替换为对基于PC的地址值进行操作但这种方式所能读取的地址范围较小并且会因地址值是否为字对齐而异。
但在ARM程序中使用LDR等指令直接将地址标号值读取到PC中实现程序跳转不是位置无关的。例如 LDR PC,main
上面的伪指令编译后的结果为 LDRPC, [PC, OFFSET_TO_LPOOL] LPOOL DCD main
可见虽然LDR是把基于PC的一个存储单元LPOOL的内容加载到PC中但该存储单元中保存的却是链接时所决定的main函数入口的绝对地址所以main函数实际所在的段不是位置无关。
② 位置无关的常量访问。在应用程序中经常要读写相关寄存器以完成必要的硬件初始化。为增强程序的可读性利用EQU伪指令对一些常量进行赋值但在访问过程中必须实现位置无关性。下面以PXA270的GPIO初始化介绍位置无关的常量访问方法。
GPIO_BASE EQU 0x40e00000; GPIO基址寄存器地址 GPDR0 EQU 0x00c; 相对于GPIO基址寄存器的偏移量 init_GPDR0 EQU 0xfffbfe00; 寄存器GPDR0初值 LDR R1, GPIO_BASE LDR R0, init_GPDR0 STR R0, [R1, #GPDR0]
上述汇编代码段经编译后的结果为
LDR R1, [PC, OFFSET_TO_GPIO_BASE] LDR R0, [PC, OFFSET_TO_init_GPDR0] STR R0, [R1, #0xc] GPIO_BASE DCD 0x40e00000 GPDR0 DCD 0x00c init_GPDR0 DCD 0xfffbfe00
可见LDR伪指令实际上使用基于PC的偏移量来对符号常量GPIO_BASE和init_GPDR0进行引用因而是位置无关的。由此可以得出如下结论使用LDR伪指令将一个常量读取到非PC的其他通用寄存器中可实现位置无关的常量访问但将一个地址值读取到PC中进行程序跳转时跳转目标则是位置相关的。
2 程序设计规范2
其他被ROPI段中的代码引用的必须是绝对地址或者是基于可读写位置无关(RWPI)段的静态基址寄存器的可写数据。
使用绝对地址只能引用被重定位到特定位置的代码段中的符号通过在位置无关代码中引入绝对地址可以让程序跳转到指定位置。例如假设Bootloader的阶段1将其自身代码拷贝到链接时所指定的SDRAM地址空间后当要跳转到阶段2的C 程序入口时可以使用指令“LDRPC, main”跳转到程序在SDRAM中的main函数入口地址开始执行。这是因为程序在编译链接时给main函数分派绝对地址系统通过将main函数的绝对地址直接赋给PC实现程序跳转。如果使用相对跳转指令“B main”那么只会跳转到启动ROM内部的main函数入口这种情况反而不能写 B main了但要写之前是不是之前 写一句 ldr pc xx也可以by imjacob。