韦东山嵌入式第一期学习笔记DAY_11——13_3_链接脚本的解析

作者:GWD 时间:2019.7.12

一、课程内容
(一)、摘要:本节课主要讲解了代码重定位的原理(链接脚本和代码重定位我在上一篇博文写了),写了一个清除bss段的代码。
1、问:简述如下重定位过程?
答:
在这里插入图片描述
.data段的load addr与runtime addr不一样将会引起代码重定位(只是引起(告诉CPU这里需要重定位),并没有实质的重定位)data段在bin文件中0x30000000的位置,程序启动后要把0x800的数据复制到0x30000000的位置,谁来做?前面的程序来做。
2、写一个打印16进制数的函数
在这里插入图片描述
在这里插入图片描述
3、问:为何执行后初始值为0的变量打印是错误的?
在这里插入图片描述
答:初始值为0的变量并不在数据段、bin文件中而是bss段,所以要对它清0操作。这是很必要的,总不能我定义几万个空的变量但这些都在bin中吧,编译器自动把这些空的变量放在bss段,我们只需要把这段清0就行了。在用keil开发时候不需要这么做是因为编译器帮我们做了。
4、问:bss段清零函数怎么写?
答:首先修改lds链接脚本,自动获取bss段的起始和终止位置,然后用汇编实现清0。
在这里插入图片描述
在这里插入图片描述
5、bss段清0后试验现象正确
在这里插入图片描述
二、学习要点
1.链接脚本中”.”表示当前位置,随时变化;

三、代码
START.S

.text
.global _start

_start:

	/* 关闭看门狗 */
	ldr r0, =0x53000000
	ldr r1, =0
	str r1, [r0]

	/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */
	/* LOCKTIME(0x4C000000) = 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]

	/* 设置CPU工作于异步模式 */
	mrc p15,0,r0,c1,c0,0
	orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA
	mcr p15,0,r0,c1,c0,0

	/* 设置MPLLCON(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]

	/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定
	 * 然后CPU工作于新的频率FCLK
	 */
	
	/* 设置内存: sp 栈 */
	/* 分辨是nor/nand启动
	 * 写0到0地址, 再读出来
	 * 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
	 * 否则就是nor启动
	 */
	mov r1, #0
	ldr r0, [r1] /* 读出原来的值备份 */
	str r1, [r1] /* 0->[0] */ 
	ldr r2, [r1] /* r2=[0] */
	cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */
	ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
	moveq sp, #4096  /* nand启动 */
	streq r0, [r1]   /* 恢复原来的值 */

	bl sdram_init
	
	/*重定位data段*/
	ldr r1, =data_load_addr/*data段在bin文件中的地址,加载地址*/
	ldr r2, =data_start/*data段在重定位地址,运行时的地址*/
	ldr r3, =data_end/*data段结束时的地址*/
cpy:
	ldrb r4,[r1]
	strb r4,[r2]
	add r1,r1,#1
	add r2,r2,#1
	cmp r2,r3
	bne cpy
	
	/*清除bss段*/
	ldr r0,=bss_start
	ldr r1,=bss_end
	mov r2,#0
clean:
	strb r2,[r0]
	add r0,r0,#1
	cmp r0,r1
	bne clean

	bl main
	
halt:
	b halt
	


SDRAM.LDS

SECTIONS
{  
  .text	0	: { *(.text) }
  .rodata	: { *(.rodata) }
  .data	0x30000000 :AT(0x800)
  { 
	data_load_addr = LOADADDR(.data);
	data_start = .;
  	*(.data)
  	data_end = .;
  }
  bss_start = .;
  .bss	: { *(.bss) *(.COMMON) }
  bss_end =.;
  }

Uart.c

#include "s3c2440_soc.h"


/* 115200,8n1 */
void uart0_init()
{
	/* 设置引脚用于串口 */
	/* GPH2,3用于TxD0, RxD0 */
	GPHCON &= ~((3<<4) | (3<<6));
	GPHCON |= ((2<<4) | (2<<6));

	GPHUP &= ~((1<<2) | (1<<3));  /* 使能内部上拉 */
	

	/* 设置波特率 */
	/* UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
	 *  UART clock = 50M
	 *  UBRDIVn = (int)( 50000000 / ( 115200 x 16) ) –1 = 26
	 */
	UCON0 = 0x00000005; /* PCLK,中断/查询模式 */
	UBRDIV0 = 26;

	/* 设置数据格式 */
	ULCON0 = 0x00000003; /* 8n1: 8个数据位, 无较验位, 1个停止位 */

	/*  */

}

int putchar(int c)
{
	/* UTRSTAT0 */
	/* UTXH0 */

	while (!(UTRSTAT0 & (1<<2)));
	UTXH0 = (unsigned char)c;
	
}

int getchar(void)
{
	while (!(UTRSTAT0 & (1<<0)));
	return URXH0;
}

int puts(const char *s)
{
	while (*s)
	{
		putchar(*s);
		s++;
	}
}

void printHex(unsigned int val)
{
	int i;
	unsigned char arr[8];
	for(i=0;i<8;i++)
	{
	arr[i] = val & 0xf;
	val >>=4;
	}

	puts("0X");

	for(i=7;i>=0;i--)
	{
	if(arr[i]>=0 && arr[i]<=9)
		putchar(arr[i]+'0');
	else
		putchar(arr[i] - 0xA + 'A');
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值