本文使用的开发板是九鼎创展的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函数去执行。
相关推荐
《S5PV210串口详解:从基础到移植printf和scanf》 S5PV210是一款基于ARM Cortex-A8内核的高性能微处理器,广泛应用于嵌入式系统和移动设备。在S5PV210的硬件体系结构中,串口(UART,Universal Asynchronous ...
三星S5PV210是一款由三星电子公司设计和制造的微处理器,也被称为RISC(Reduced Instruction Set Computer,精简指令集计算机)微处理器。该芯片在2009年1月首次发布,后续在2010年5月发布了修订版1.10版本的数据...
- **移动设备**: 智能手机和平板电脑是S5PV210的主要应用场景之一,其高性能和低功耗特性非常适合这类设备。 - **车载信息系统**: 由于具备强大的多媒体处理能力,S5PV210也被广泛应用于汽车娱乐系统。 - **数字标牌...
《S5PV210_UM_REV1.1 文档》是针对三星S5PV210处理器的一份详尽的技术手册,这份文档主要涵盖了该处理器的架构、功能特性、接口规范以及应用开发等方面的知识。S5PV210是一款高性能、低功耗的ARM Cortex-A8核心的微...
《S5PV210芯片数据手册 Cortex-A8内核详解》 S5PV210是一款基于Cortex-A8核心的高性能应用处理器,由三星公司设计,广泛应用于智能手机、平板电脑以及各种嵌入式系统中。这款芯片以其强大的处理能力和高效能闻名,...
根据提供的文件信息,我们可以深入探讨S5PV210这款微处理器在硬件PCB设计方面的关键要点。S5PV210是一款基于ARM架构的RISC(精简指令集计算机)微处理器,常用于嵌入式系统开发。下面将详细介绍与S5PV210相关的硬件...
标题 "s5pv210外部中断裸机程序" 涉及的是三星S5PV210处理器的外部中断处理机制。S5PV210是一款基于ARM Cortex-A8内核的微处理器,常用于嵌入式系统设计,如平板电脑、智能设备等。在裸机环境下编程意味着不依赖任何...
S5PV210开发板是一种基于三星S5PV210处理器的开发平台,常用于嵌入式系统的学习和开发。S5PV210处理器是一款高性能的ARM Cortex-A8微处理器,具有丰富的外设接口和强大的处理能力,适用于智能设备和移动设备的开发。...
这是一个S5PV210的完整头文件,包含各类宏定义!欢迎下载!
《S5PV210源码详解:走进嵌入式世界》 S5PV210是一款由三星公司推出的高性能、低功耗的ARM Cortex-A8处理器,广泛应用于嵌入式系统、移动设备以及智能硬件等领域。对于学习和开发基于S5PV210的系统,理解其源码是至...
三星S5PV210是一款由三星电子设计的RISC微处理器,常用于移动计算设备和嵌入式系统。这份数据手册提供了关于S5PV210处理器的详细技术信息,包括寄存器介绍和官方文档。文档指出,虽然手册中的信息在发布时被认为是...
该压缩包包含以下信息 《Application Note(Internal ROM Booting)》NOV 23, 2009Preliminary REV 0.3; 《Circuit Design Guide...《SMDK_S5PV210_CPU B'd (S5PV210 Evaluation Board) Schematics》Rev 0.0 2009. 09;
《S5PV210:全面解析数据手册与寄存器详解》 S5PV210是一款由Samsung公司推出的高性能、低功耗的ARM Cortex-A8处理器,广泛应用于移动设备、嵌入式系统和物联网(IoT)设备中。这款处理器的核心特性在于其强大的处理...
在本文中,我们将深入探讨如何进行S5PV210微处理器上的u-boot移植过程,以及如何使用提供的详细教程和工程实例。S5PV210是一款由Samsung开发的高性能ARM Cortex-A8核心的系统级芯片(SoC),广泛应用于嵌入式系统和...
在嵌入式系统领域,S5PV210是一款由Samsung公司推出的高性能ARMCortex-A8处理器,广泛应用于各种嵌入式设备,如智能手机、平板电脑等。在本主题中,我们将深入探讨如何利用S5PV210的Timer0模块来输出PWM信号,进而...
"基于S5PV210的Linux内核移植" 本文主要介绍了将Linux内核移植到基于S5PV210处理器的嵌入式系统中的方法和步骤。该方法包括搭建基于Cortex-A8的Linux开发环境、Linux内核的配置和编译、内核移植的步骤等。 Linux...
《S5PV210:三星嵌入式处理器的深度解析》 S5PV210,这款由三星推出的嵌入式处理器,以其强大的性能和广泛的适用性在MID(移动互联网设备)和GPS领域备受瞩目。作为一款基于ARM Cortex-A8内核的处理器,它在设计上...
【S5PV210 PWM定时器】是三星公司推出的一款基于ARM Cortex-A8处理器的SoC(系统级芯片)中的重要硬件模块。PWM(Pulse Width Modulation,脉宽调制)定时器在嵌入式系统中广泛用于电机控制、LED亮度调节、模拟信号...
**S5PV210处理器详解** S5PV210是三星电子推出的一款高性能、低功耗的ARM架构处理器,特别适用于移动设备和嵌入式应用,如智能手机、平板电脑以及工业控制系统。该处理器在Android平台上表现出色,为开发者提供了...
S5PV210的亮点之一是其集成的多格式编解码器(MFC),支持MPEG-1/2/4、H.263、H.264的编码与解码,以及VC1、Divx的解码,覆盖了主流视频格式,适用于各种多媒体应用场景。 #### 内存接口优化 为了适应高端通信服务...