能用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符号表?
- 对于常规变量g_i,得到里面的值,使用&g_i得到addr;
- 为了保持代码的一致,对于lds中的a1,使用&a1得到里面的值;
这只是一个编译器的小技巧,不用深究。
结论:
- C程序中不保存lds文件中的变量,lds再大也不影响;
- 借助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
再观察上述打印结果