014 JZ2440代码重定位(二)---lds脚本

本文详细介绍了在S3C2440和JZ2440平台进行代码重定位的过程,通过lds链接脚本实现更高效的内存管理。内容包括为何使用lds脚本,如何通过Makefile调用lds文件,以及如何分析和配置链接脚本,以减少bin文件大小。在完成重定位后,还需在start.S中初始化SDRAM并复制data段,确保全局变量和静态变量在SDRAM中正确工作。

在上一章中我们引入了为什么要使用代码重定位。

那么本章我们要讲解代码重定位的具体实现。

在实现的重定位的时候,我们需要引入链接脚本的概念。

也就是我们把代码重定位的起始和结束,具体内容的放置等等这些配置放到一个文件中。

然后由Makefile在编译的过程中来调用这个 *.lds 文件,然后执行代码的各个段的位置配置。

 

首先我们做了一个实验,在不实用lds链接脚本的情况下,直接在Makefile中做代码重定位。

然后发现生成的bin文件多达800M之多。

如上图,将 -Tdata 段(全局变量和static变量)设置放到SDRAM中,0x30001000处。

编译后可以看到:

有800MB+的内存占用。

查一下反汇编的dis文件可以看到:

我们实际代码结束段和我们重定向data的地址差

中间跨过的地址空间占0x30000000-0x3cc = 30000C34  (这中间的巨大空白脚 Hole)

 

所以为了缩小bin文件的大小我们才使用了lds文件。

将Makefile修改如下:

然后设置 sdram.lds文件:

在这里为什么我们的lds文件要写成这样的格式:

请参考链接:http://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html

这里有规定链接脚本的格式,如何定义变量等等规则。

再看下我们的代码分布:

然后我们分析一下这个链接脚本的具体配置:(后面写这个链接脚本的时候我把重定位地址改成了0x30000000而不是前面的0x30001000, 当然这个地址只要是在SDRAM范围内都可以)

//首先这个Section是固定格式
SECTIONS{
     
    // text存放的是我们的代码段
	.text 0 : { *(.text) }

    // rodata存放的是我们的只读数据段
	.rodata : {*(.rodata)}

    //0x30000000 这里是我们声明全局变量和静态变量存放的地址
    //0x800是全局变量和静态变量实际的存放地址
	.data 0x30000000 : AT(0x800) 
	{
        //LOADADDR(.data):data段在bin文件的地址。 data_load_addr是我们定义的一个变量
		data_load_addr = LOADADDR(.data);
        //CPU去数据的地址, 这里的 "."表示当前地址,
		data_start = .;
        //存放全局变量和静态变量数据的长度
		*(.data)
        //当前地址,也就是存放全局和静态变量后的地址
		data_end = .;
	}
    //存放bss段和注释段
	.bss : {*(.bss) *(.COMMON)}
}

完成后我们还需要初始化sdram,并且把data段从bin文件中拷贝到SDRAM。只有当这些准备工作都完成无误后,CPU在指定的重定位地方才能读到全局变量和静态变量。

这部分工作需要在start.S中还没进入到main之前完成。

.text
.global _start

_start:

	/*stop watchdog*/
	ldr r0, =0x53000000
	ldr r1, =0x00
	str r1,[r0]

	/* config MPLL FCLK : HCLK : PCLK = 400MHz : 100MHz : 50MHz */
	/* LOCKTIME = 0xFFFFFFFF */
	ldr r0, =0x4C000000
	ldr r1, =0xFFFFFFFF
	str r1, [r0]

	/* CLKDIVN(0x4C000014) = 0x5
	 * tFCLK : tHCLK : tPCLK = 1:4:8
	 */
	ldr r0, =0x4C000014
	ldr r1, =0x5
	str r1, [r0]

	/* config CPU mode asynchronization */
	mrc p15,0,r0,c1,c0,0
	orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA
	mcr p15,0,r0,c1,c0,0

	/* config MPLL(0x4C000004) = (92<<12) | (1<<4) | (1<<0) 
	 *  m = MDIV+8 = 92+8=100
	 *  p = PDIV+2 = 1+2 = 3
	 *  s = SDIV = 1
	 *  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M
	 */
	ldr r0, =0x4C000004
	ldr r1, =(92<<12) | (1<<4) | (1<<0)
	str r1, [r0]
	/* notice: once config valid,
	 * CPU will work at new FCLK
	 */
	 

	/* config sp, estimate whether initial
     * from NOR flash or NAND flash
     * test method:
     * write 0 to start address
     * read data from 0 address,
     * if read data is 0, then initial from NAND flash
     * if read data not equal to 0, then initial from NOR flash
	 */
	mov r1, #0
	ldr r0, [r1] /*read out src value for backup*/
	str r1, [r1] /* 0->[0] */
	ldr r2, [r1] /* r2 = 0 */
	cmp r1, r2   /* if r1==r2 nand initial, else nor initial*/
	ldr sp, =0x40000000 + 1024*4 /* assumption initial from nor */
	moveq sp, #1024*4 /* initial from nand */
	streq r0, [r1] /* recovery src value */

	/* init sdram */
	bl sdram_init

	/* relocate data */
	ldr r1, =data_load_addr  /* data段在bin文件中的地址, 加载地址  */
	ldr r2, =data_start		 /* data段在重定位地址, 运行时的地址 */
	ldr r3, =data_end		 /* data段结束地址 */

	/* 把data段从r1的地方拷贝到r2的地方 */
cpy:
	ldrb r4, [r1]
	strb r4, [r2]
	add r1, r1, #1
	add r2, r2, #1
	cmp r2, r3
	bne cpy

	bl main

halt:
	b halt

 

从sdram_init到 跳转至main之前的部分都是在做重定向工作。

这个时候我们再次编译code。可以看到:

bin文件从800MB+一下变成2KB+了。

烧录到NorFlash后看下串口的现象:

全局变量的值可以改变了。

说明我们重定位成功了。全局变量在SDRAM中,所以在执行自增的时候,变量值可以改变。

main代码如下:

/**
  ******************************************************************************
  * @file      : main.c  
  * @version   : none
  * @date      : 2019-09-02
  * @brief     : test led & uart
  ******************************************************************************
  * @attention : JZ2440
  * @author    : shao15232
  * @personal  : shao15232 work stdio
  ******************************************************************************
  */
#include "led.h"
#include "uart.h"

char g_char = 'A';
const char g_char2 = 'B';
int g_A = 0;
int g_B;

void delay(unsigned int count)
{
	while(count--);
}

int main(void)
{
	unsigned char c;
	
	uart_init();

	puts("Hello, Welcome to JZ2440 world!\r\n");
		
	while(1)
	{
		putchar(g_char);
		g_char++;
		delay(1000000);
	}

	return 0;
}


/* This experiment is test for nand flash and nor flash distinction
 * if initial from nand flash, then g_char variable will increase by itself
 * if initial from nor flash, then nor flash can't write. then g_char can,t increase itself.
 * it's will always putchar AAAA....
 */

 

再看下反汇编dis中g_A、g_B的地址:

在我们重定向的0x30000000开始的地方

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值