代码重定位

发布者:EnchantedBreeze最新更新时间:2024-07-31 来源: cnblogs关键字:代码重定位  S3C2440  启动过程 手机看文章 扫描二维码
随时随地手机看文章

1 说明

实验平台:     JZ2440

CPU:     S3C2440

 

2 S3C2440的启动过程

图1 S3C2440A Memory Map after Reset

 

S3C2440支持从多种存储设备启动:NOR/NAND Flash, EEPROM, 等等。芯片内部有4K SRAM用于启动设备使用。至于,设备最终以哪一种方式启动,通过配置芯片的OM引脚,由芯片内部实现。

 

摘自《S3C2440A_UserManual_Rev13》:

                        图2 BANK0 BUS WIDTH

 

举个例子,当选择以NOR Flash的方式启动时,芯片的0地址(4K地址空间)会直接映射到Nor Flash上,CPU直接从Nor Flash读取指令,并执行;当选择以Nand Flash启动时,S3C244会把Nand Flash的前4K数据,复制到芯片内部SRAM中,然后CPU从内部SRAM读取指令,并执行。(NOR Flash 是由内存控制器直接驱动的,而NAND Flash是由NAND Flash控制器驱动的,NAND Flash控制器则由内存控制器驱动,因此NOR Flash是CPU统一编址的,而NAND Flash不是,因此他们间的启动方式是有区别的)。

 

3 分析可执行文件

*.elf与*.bin文件的区别

bin文件:二进制文件,只包含机器码;可在机器中直接运行。

elf文件:除了机器码外,还包含其他额外的信息,例如:段的运行地址,加载地址,重定位表,符号表等等;只能运行于带操作系统的机器,经操作系统解析(提取出机器码)后执行;可用于调试。

通过'arm-linux-ld -T target.lds *.o -o *.elf'链接得到*.elf文件;然后通过'arm-linux-objcopy -O binary -S *.elf *.bin'把*.elf转换成*.bin文件。

 

4 链接脚本

4.1 程序的组成

程序由代码段、数据段、只读数据段、BSS段、注释段组成,其中BSS段、注释段不存放于bin文件或elf文件中。

.text:    代码段;程序中的可执行部分。

.data:    数据段;程序中的全局变量。

.rodata:    只读数据段;程序中的const类型变量。

.bss:    BSS段;程序中未初始化的或初始值为0的全局变量。

.COMMON:    注释段。

注意:局部变量是随着函数的调用,在栈中分配,并在函数退出时释放。

 

4.2 链接脚本说明

当不适用链接脚本指示链接器进行连接时,链接的顺序按照Makefile中,文件的放置顺序进行链接,注意把start.o防置在最前面,否则程序运行会出错。Makefile中使用链接脚本:[-T *.lds]。

 

链接脚本的格式:

    SECTIONS{

        secname start Block(align) (NOLOAD) : AT(ldadr)

        {

contents > region : phdr = fill

}

}

 

示例:

图3 链接脚本示例说明

 

注意:链接脚本中,每个段的起始地址应当设置为4字节对齐,因为汇编指令会自动把需要操作的地址,自动进行4字节对齐,如果我们对一个非4字节对齐的地址进行操作,会出现意想不到的错误。

例如:

    ldr r1, =0x32000000

    ldr r2, =0

    str r2, [r1]

我们期望的结果是,[0x32000000] = 0;但是实际的结果是[0x30000000] = 0;这不是我们想要的。

 

5 代码重定位

5.1 代码重定位的意义

从NOR Flash启动的角度分析:

程序可以直接在NOR Flash上执行。NOR Flash可以通过地址直接读取,但是不能直接执行写操作,必须通过特定的操作,才能实现写操作,因此在NOR Flash上则行程序,其全局变量是无法更改的,因此,我们需要把烧写到NOR Flash上的程序重新重定位到SDRAM上。

 

从NAND Flash启动的角度分析:

程序不可以直接在NAND Flash上执行;通过配置OM引脚,当选择NAND Flash为启动方式时,芯片内部固件会把NAND Flash的前4K复制到内部SRAM,程序从SRAM的0地址开始执行,当程序超过4K时,为了保证程序能正常运行,一般前4K的代码实现把程序复制到SDRAM上,然后在SDRAM上执行程序。

 

特别说明:在函数内部声明一个已初始化的数组,数组的元素是存放于代码段的;在调用这个函数时,会声明一个局部变量的指针(数组名),使该指针指向数组元素位于代码段的首地址,完成初始化动作,因此,未重定位之前,不能使用数组。

 

5.2 重定位的方式

5.2.1 lds文件中的变量

通过对lds文件中的变量进行赋值,在C函数中,通过外部声明,可以获取对应段的地址信息。

            图4

 

实际上,lds文件中的变量,并不会保存在程序中,编译程序时,有一个符号表(Symbol Table)保存lds中的变量,当程序需要使用lds中的变量时,通过声明外部变量的方法,通过取值,获取变量的值。例如:extern int name;target = &name;。

图5 Symbol Table

 

5.2.2 重定位的方式

只重定位数据段:

程序运行过程中,只有程序中的数据段和BSS段是可能被代码段修改的,因此在程序运行后,可以只把程序中的数据段以及BSS段重新定位到SDRAM中。

在程序运行中,只需把存放于加载地址的数据段、BSS段,重新定位到运行时地址所指示的位置即可。

 

重定位整个程序:

在程序运行后,把整个程序重新定位到SDRAM中。

 

5.2.3 位置无关码

b/bl指令是相对跳转指令,跳转的目标地址只与当前PC值有关,与运行时地址无关,因此虽然烧写到NOR Flash上的程序的运行时地址指向SDRAM存储空间的起始地址(这里是0x30000000),由于b/bl是相对跳转的,因此,只要在完成重定位操作之前,不涉及全局变量、静态变量的操作,程序可以正常运行。通过操作相对地址指令实现的代码,也称为位置无关码。

注意,重定位完成后,需要跳转到C函数去执行程序时,应该使用绝对跳转(直接修改PC值),而不能使用相对跳转,否则无法跳到SDRAM上去执行。

 

附录1 程序源码

Makefile

 

target.lds

 

Start.S

 

Relocate.c

 

附录2 参考文档

《S3C2440用户手册》

《The GNU linker》


关键字:代码重定位  S3C2440  启动过程 引用地址:代码重定位

上一篇:点亮一个LED之参数传递规则
下一篇:系统时钟的配置

推荐阅读最新更新时间:2024-11-11 12:08

s3c2440串口接收中断(OK2440III)
#include uart2440.h #include def.h #include 2440addr.h #include led2440.h // 引入led #define UART_CLK 50000000 // UART0的时钟源设为PCLK #define UART_BRUD(baud) { rUBRDIV0 = ((UART_CLK / (baud * 16)) - 1) } void __irq uart_irq_recv(void) { uint8 buf_recv; uint8 buf = 接收中断发生...rn ; uart_send(buf); buf_recv
[单片机]
S3C2440之简易播放器设计(利用DMA与IIS通信)
利用前一篇文章讲解的IIS知识,只是不是利用轮询,而是利用DMA控制器,让数据在内存和IIS的发送FIFO之间传送。这样在音乐播放过程中,进行暂停,静音,播放,音量增减都不会使音乐产生卡顿的感觉。 注意DMA的请求是由发送FIFO自动发起的。 可以设置DMAMSKTRIG的STOP位停止DMA,但是真正的停止需要参考ON_OFF位。ON_OFF位当为非自动重载,且CURR_TC为0,该位自动为OFF。STOP位置位,该位也置为OFF。所以需要注意,一次DMA传输结束,假设开启了DMA中断,那么再DMA中断需要再次打开DMA,因为CURR_TC=0使其停止了。 当CURR_TC=0,且DMA ACK=1的话,TC的数值又
[单片机]
变频器在启动过程中应该注意的问题
变频器的输入6kV电源高压开关必须待变频器给出的“高压合闸允许”信号时,才能合闸;   如果变频器始终没有提供“高压合闸允许”信号,请确认 变频器 控制电源是否合上,柜门是否关好,旁通柜隔离开关是否正确到位,变频器本身是否处于故障状态,以及和变频器相关的系统信号是否正确;   每次分断6kV高压开关后,必须至少在160秒后方可再次送电;   旁通柜隔离开关处在变频位置时,用户6kV高压开关合闸只相当于给变频器送电,电机并不启动。需要启动电机,还必须给变频器发运行命令指令;   启动变频器以前,风机挡板或水泵出口阀门最好处于关闭位置。并确认电机没有因为挡板或出口阀门不严和其他原因而反转,否则容易引起变频器启动时过流停机;
[嵌入式]
s3c2440裸机-代码定位-2-编程实现
代码重定位(2.编程实现代码重定位) 1.引入链接脚本 我们上一节讲述了为什么要重定位代码,那么怎么去重定位代码呢? 上一节我们发现 arm-linux-ld -Ttext 0 -Tdata 0x30000000 这种方式编译出来的bin文件有800多M,这肯定是不行的,那么需要怎么把.data段重定位到sdram呢? 可以通过AT参数指定.data段在编译时的存放位置,我们发现这样指定太不方便了,而且不好确定要放在bin文件的哪个位置。这里就要引入链接脚本,它可以帮我们解决这个不必要的麻烦。 链接脚本格式 格式如下图: 我们来看一个具体的例子: SECTIONS { . = 0x00000000; //表示当前
[单片机]
反汇编解析S3C2440汇编点灯
代码 首先回顾代码 /* *点亮LED:GPF4 */ .text //表明它是代码段 .global _start _start: /*配置GPF4为输出引脚 *把0x100写到地址0x56000050上,熄灭led */ ldr r1, =0x56000050 /*将这个地址存放到r1中*/ ldr r0, =0x100 /*或者使用 mov r0, #0x100 将0x100放入r0 */ str r0, /*将r0的值写入到r1的地址中*/ /*设置GPF4输出高电平 *把0x00写到地址0x56000054上,点亮led */ ldr r1, =0x56000054
[单片机]
反汇编解析<font color='red'>S3C2440</font>汇编点灯
三星s5pv210启动过程(ARM Cortex-A8)
S5PV210内部有96Kb的IRAM和64Kb的IROM。 DRAM0的地址:0x2000_0000——0x3FFF_FFFF(512MB)(自带内存) DRAM1的地址:0x4000_0000——0x7FFF_FFFF(1024MB)(扩展内存) SROM的地址: 0x8000_0000——0xAFFF_FFFF(128MB*6)(扩展内存) IROM的地址: 0xD000_0000——0xD000_FFFF(64Kb) ISRAM的地址: 0xD002_0000——0xD003_7FFF(96Kb) SFR的地址: 0xE000_0000——0xFFFF_FFFF(512Mb) IROM结构: BL0:64Kb。 ISRA
[单片机]
tiny4412裸机程序——代码定位
在前面介绍exynos4412芯片启动过程时,我们知道:一上电,exynos4412首先执行固化在iROM中的代码,iROM首先设置程序运行环境(比如关看门狗、关中断、关MMU、设置栈、设置栈、启动PLL等),然后根据OM引脚确定启动设备(NAND Flash/SD卡/其他),把BL1从里面读出存入iRAM的0x02021400地址处,然后开始启动BL1;BL1从SD卡适当的位置读入14K字节的数据,存在iRAM地址0x02023400处,所以BL2不能大于(14K–4) 字节,这里引出了为什么写这一节的原因:如果我们的程序很大,大于14K怎么办? 运行地址和链接地址: 运行地址是程序当前所处的地址,即程序在运行时,所处的
[单片机]
S3C2440在MDK4.22下使用printf向串口打印调试
背景知识: 串口的基本知识已经在上一篇讲过了。这里重点讲解如何在MDK4.22下使用printf函数,这样的话就可以很方便的打印调试信息,追踪。 这个知识来源于MDK自带的帮助手册。有现成的代码提供。 实现方式有2种,使用标准C库下裁剪合适的函数,使用微库C下裁剪合适的函数。 微库下的情况,在魔术棒那里要勾选上使用微库。然后需要定义如下结构和改写如下函数--FILE stdout fputc ferror。 标准库的情况,也是需要关注FILE stdout fputc ferror。注意网上很多文章说,在标准库下,需要关掉半主机模式,我尝试过,关掉后,需要定义_sys_exit函数,可以达到效果,但是如果不关掉半主机模式,和
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved