本文使用的开发板是九鼎创展的X210 iNand版本。
本文要完成的功能是:在SRAM中将代码从0xd0020010重定位到0xd0024000(本来代码是运行在0xd0020010的,但我们又希望代码实际是在0xd0024000位置运行的,这时就需要重定位了)。
一、思路分析
(1)通过链接脚本将代码链接到0xd0024000
(2)dnw下载时将bin文件下载到0xd0020010
(3)代码执行时,通过代码前段的少量PIC位置无关码将整个代码搬移到0xd0024000
(4)使用一个长跳转,跳转到0xd0024000处的代码继续执行,重定位完成
通过(1)和(2)就保证了代码实际下载运行在0xd0020010,但是却被链接在0xd0024000,从而为重定位奠定了基础。当我们把代码链接地址设置为0xd0024000时,实际隐含意思就是这个代码将来必须放在0xd0024000位置才能正确执行。如果实际运行地址不是0xd0024000就要出事(除非代码是PIC位置无关码)。
当我们执行完代码重定位后,实际上在SRAM中有2份代码的镜像:一份是我们下载到0xd0020010处开头的,另一份是重定位代码复制到0xd0024000处开头的,这两份内容完全相同,仅仅地址不同。重定位之后使用ldr pc, =led_blink这句长跳转直接从0xd0020010处的代码跳转到0xd0024000开头的那份代码的led_blink函数去执行(实际上此时在SRAM中有2个led_blink函数的镜像,两个都能执行。如果短跳转bl led_blink则执行的就是0xd0020010开头的这一份,如果长跳转ldr pc, =led_blink则执行的就是0xd0024000开头的这一份)。
当链接地址和运行地址相同时,短跳转和长跳转实际效果是一样的。当链接地址和运行地址不同时,短跳转实际执行的是运行地址处的那一份代码,而长跳转执行的是链接地址处的那一份代码。
通过以上信息,就知道重定位代码的作用是:在PIC位置无关码执行完之前(代码中第一句位置有关码执行之前)必须将整个代码搬移到0xd0024000位置去执行。
二、代码实现
1、Makefile
led.bin: start.o led.o arm-linux-ld -Tlink.lds -o led.elf $^ arm-linux-objcopy -O binary led.elf led.bin arm-linux-objdump -D led.elf > led_elf.dis gcc mkv210_image.c -o mkx210 ./mkx210 led.bin 210.bin %.o : %.S arm-linux-gcc -o $@ $< -c -nostdlib %.o : %.c arm-linux-gcc -o $@ $< -c -nostdlib clean: rm *.o *.elf *.bin *.dis mkx210 -f
2、链接脚本(link.lds)
SECTIONS { . = 0xd0024000; .text : { start.o * (.text) } .data : { * (.data) } bss_start = .; .bss : { * (.bss) } bss_end = .; }
3、start.S
#define SVC_STACK 0xD0037D80 .global _start _start: // 设置SVC栈 ldr sp, =SVC_STACK // 重定位 // adr指令用于加载_start当前的运行地址 adr r0, _start // ldr指令用于加载_start的链接地址:0xd0024000 ldr r1, =_start // bss段的起始地址 ldr r2, =bss_start // 重定位代码的结束地址,重定位只需重定位代码段和数据段即可 // 比较_start的运行地址和链接地址是否相等 cmp r0, r1 // 如果相等说明不需要重定位,所以跳过copy_loop,直接到clean_bss beq clean_bss // 用汇编实现的一个while循环 copy_loop: ldr r3, [r0], #4 // 源 str r3, [r1], #4 // 目标 这两句代码就完成了4个字节内容的拷贝 cmp r1, r2 // r1和r2都是用ldr加载的,都是链接地址,所以r1不断+4总能等于r2 bne copy_loop // 清bss段,其实就是在链接地址处把bss段全部清零 clean_bss: ldr r0, =bss_start ldr r1, =bss_end cmp r0, r1 // 如果r0等于r1,说明bss段为空 beq run_on_dram // 清除完bss之后的地址 mov r2, #0 clear_loop: str r2, [r0], #4 // 先将r2中的值放入r0所指向的内存地址,然后r0 = r0 + 4 bne clear_loop run_on_dram: // 长跳转到led_blink开始第二阶段 ldr pc, =led_blink b .
4、led.c
#define GPJ0CON 0xE0200240 #define GPJ0DAT 0xE0200244 #define rGPJ0CON *((volatile unsigned int *)GPJ0CON) #define rGPJ0DAT *((volatile unsigned int *)GPJ0DAT) void delay(void); void led_blink(void) { rGPJ0CON = 0x11111111; while(1) { // led亮 rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5)); // 延时 delay(); // led灭 rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5)); // 延时 delay(); } } void delay(void) { volatile unsigned int i = 900000; while (i--); }
重定位就是汇编代码中的copy_loop函数,代码的作用是使用循环结构来逐句复制代码到链接地址。复制的源地址是SRAM的0xd0020010,复制的目标地址是SRAM的0xd0024000,复制的长度是bss_start - _start,所以复制的长度就是整个重定位需要重定位的长度,也就是整个程序中代码段 + 数据段的长度,bss段(bss段是初始化为0的全局变量)不需要重定位。
清除bss段是为了满足C语言的运行时要求(C语言要求显式初始化为0的全局变量,或者未显式初始化的全局变量的值为0),实际上C语言编译器就是通过清bss段来实现C语言的这个特性的。一般情况下我们的程序是不需要负责清bss段的,因为C语言编译器和链接器会帮我们的程序自动添加一段头程序,这段程序会在main函数之前运行,这段代码就负责清除bss。但是在我们代码重定位了之后,因为编译器帮我们附加的代码只是帮我们清除了运行地址那一份代码中的bss,而未清除重定位地址处的那一份代码的bss,所以重定位之后需要自己去清除bss。
清理完bss段后重定位就结束了。此时的状况是:
(1)当前运行地址还在0xd0020010开头的那份代码中运行着
(2)SRAM中已经有了2份代码,1份在0xd0020010开头,另一份在0xd0024000开头
最后执行ldr pc, =led_blink这句长跳转直接从0xd0020010处的代码跳转到0xd0024000开头的那份代码的led_blink函数去执行。
相关推荐
### U-Boot 移植至 S5PV210 的详解 #### 一、程序流程分析 U-Boot 的启动过程对于理解整个系统的初始化是非常重要的。以下是对基于 S5PV210 平台的 U-Boot 启动流程进行的深入解析。 - **Start.S** 是 U-Boot 的...
《Dragin用户指南1.21:三星S5PV210 WinCE烧写工具详解》 一、引言 Dragin用户指南1.21是针对三星S5PV210 WinCE烧写工具的一份详尽说明文档,旨在为用户提供关于此工具的全面理解和操作指导。该文档于2009年8月14...
本教程旨在指导读者完成s5pv210平台的u-boot移植,涵盖了移植的整个流程,包括程序流程分析、移植u-boot-spl、支持串口、DECLARE_GLOBAL_DATA_PTR、加载Uboot到RAM、Uboot重定位、移植网卡DM9000A驱动等内容。...
《S5PV210处理器的重定位技术详解》 在嵌入式系统领域,处理器的重定位是一项至关重要的技术,特别是在使用S5PV210这种高性能微处理器时。S5PV210是由三星电子开发的一款基于ARM Cortex-A8内核的SoC(System on ...
S5PV210是一种广泛应用于嵌入式系统开发的处理器,具有较高的性能和较低的能耗,是友善之臂公司生产的一款产品。 ### 知识点一:裸机程序开发基础 裸机程序开发是指直接在硬件上编写程序,不依赖于操作系统。在S5...
在嵌入式系统,尤其是基于特定处理器如S5PV210的系统中,对DDR内存的初始化和重定位是非常关键的步骤,因为它们直接影响到系统的启动性能和稳定性。 S5PV210是一款由Samsung开发的高性能、低功耗的应用处理器,集成...
该指南详细介绍了如何使用Mini210S开发板以及S5PV210处理器进行裸机程序开发,涵盖硬件启动、内核移植、驱动开发等多个层面。 首先,教程从汇编语言开始,引导开发者点亮LED,进一步过渡到使用C语言编程,以此逐步...
本次移植的目标平台是OK6410开发板,该开发板基于三星S5PV210芯片,内置了256MB DDR内存和2GB NAND Flash存储空间,具备丰富的外设接口,非常适合用于嵌入式系统的开发。 #### 二、移植环境配置 移植u-boot-2012....