韦东山嵌入式Linux学习笔记之——代码重定位005_重定位和清除BSS段的C函数实现

能用C函数就不要用汇编。

进入start.S中修改代码:


任务就是在init.c中分别实现上述两个C函数。

void copy2sdram(volatile unsigned int *src, volatile unsigned int *dest, unsigned int len)   /* src(r1), dest(r2), len(r2-r1) */
{
	unsigned int i = 0;
	
	while(i < len)
	{
		*dest++ = *src++;
		i += 4;
	}	
	
}

void clean_bss(volatile unsigned int *start, volatile unsigned int *end)  /* start_addr(r1), end_addr(r2) */
{
	while(start <= end)
	{
		*start++ = 0;
		
	}
}

汇编中,为C语言传入的参数,依次就是R1、R2、R3。 编译,烧写运行没有问题。

现在还有一个问题就是C函数的参数是由汇编语言传入的,那么能不能够将这一部分汇编代码也变成C语言来实现呢?

	/* 重定位text、rodata、data段整个程序 */
	bl copy2sdram   /* src(r1), dest(r2), len(r2-r1) */
	
	
	/* 清除BSS段 */
	bl clean_bss  /* start_addr(r1), end_addr(r2) */
现在要做的是在C函数中去链接脚本中获取所需要的参数。


① 为了让程序更具有通用性,首先在链接脚本中定以__code_start为当前地址。

	. = 0x30000000;

	__code_start = .;

② 然后在C函数中定义指针指向这些地址所在的位置。

void copy2sdram(void)   
{
	/* 要先从lds文件中获得__code_start, __bss_start
	 * 然后从0地址处将数据复制到__code_start地址处
	 */

	extern int __code_start, __bss_start;
	
	volatile unsigned int *dest = (volatile unsigned int *)&__code_start;
	volatile unsigned int *src = (volatile unsigned int *)&0;	
	volatile unsigned int *end = (volatile unsigned int *)&__bss_start;
		
	while(dest < end)
	{
		*dest++ = *src++;
	}	
	
}

void clean_bss(void)  
{	
	/* 要先从lds文件中获得__bss_start, _end */
	
	extern int __bss_start, _end;
	
	volatile unsigned int *start = (volatile unsigned int *)&__bss_start;
	volatile unsigned int *end = (volatile unsigned int *)&_end;

	while(start <= end)
	{
		*start++ = 0;
		
	}
}
编译烧写之后程序正常运行。


总结:



C代码中如何使用链接脚本中定义的变量
http://www.100ask.org/bbs/forum.php?mod=viewthread&tid=16231&highlight=%C1%B4%BD%D3%BD%C5%B1%BE


参考文章:https://sourceware.org/ml/binutils/2007-07/msg00154.html


C函数怎么使用lds文件中的变量abc?
a. 在C函数中声明改变量为extern类型, 比如:
    extern int abc;

b. 使用时, 要取址, 比如:

     int *p = &abc;  // p的值即为lds文件中abc的值(在lds文件中,变量的值即为段地址)。

原因:



汇编文件中可以直接使用外部链接脚本中的变量,但C函数中要加上取址符号。 解释一下原因: C函数中,定义一个全局变量int g_i;,程序中必然有4字节的空间留出来给这个变量g_i

假如我们的lds文件中有很多变量 lds{ a1 = ; a2 = ; a3 = ; ... } 如果我们C程序只用到几个变量,完全没必要全部存储lds里面的所有变量,C程序是不保存lds中的变量的。 对于万一要用到的变量,编译程序时,有一个symbol table符号表:


如何使用symbol table符号表?

  1. 对于常规变量g_i,得到里面的值,使用&g_i得到addr;
  2. 为了保持代码的一致,对于lds中的a1,使用&a1得到里面的值;

这只是一个编译器的小技巧,不用深究。

结论:

  1. C程序中不保存lds文件中的变量,lds再大也不影响;
  2. 借助symbol table保存lds的变量,使用时加上"&"得到它的值,链接脚本的变量要在C程序中声明为外部变量,任何类型都可以;



作业:

(1).使用printf函数打印以下信息:
volatile unsigned int *dest = (volatile unsigned int *)&__code_start;
volatile unsigned int *end = (volatile unsigned int *)&__bss_start;
volatile unsigned int *src = (volatile unsigned int *)0;
a. 打印dest, end, src的值
b. 打印dest, end, src所指向的地址的值


(2). 修改链接脚本,把程序重定位到0x32000000
     再观察上述打印结果












猜你喜欢

转载自blog.csdn.net/u011663005/article/details/81043613