码迷,mamicode.com
首页 > 编程语言 > 详细

C语言引用连接脚本lds中的符号——清除bss段,c实现方式

时间:2017-12-20 04:01:23      阅读:338      评论:0      收藏:0      [点我收藏+]

标签:ram   理解   启动   ali   img   引用   使用   文件   unsigned   

之前我们的启动文件清除bss和拷贝都是通过汇编的方式的实现,但是,我们能够使用C语言,就不使用汇编:

先看连接脚本:

SECTIONS
{
    . = 0x30000000;

    __code_start = .;

    . = ALIGN(4);
    .text      :
    {
      *(.text)
    }

    . = ALIGN(4);
    .rodata : { *(.rodata) }

    . = ALIGN(4);
    .data : { *(.data) }

    . = ALIGN(4);
    __bss_start = .;
    .bss : { *(.bss) *(COMMON) }
    _end = .;
}

现在我们编写C语言的copy和clean函数,但是在我们的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 *end = (volatile unsigned int *)&__bss_start;
    volatile unsigned int *src = (volatile unsigned int *)0;

    while (dest < end)
    {
        *dest++ = *src++;
    }
}


void clean_bss(void)
{
    /* 要从lds文件中获得 __bss_start, _end
     */
    extern int _end, __bss_start;

    volatile unsigned int *start = (volatile unsigned int *)&__bss_start;
    volatile unsigned int *end = (volatile unsigned int *)&_end;


    while (start <= end)
    {
        *start++ = 0;
    }
}

 

start.S部分展示:

技术分享图片

先不管连接脚本的引用,我们现在讨论一个问题,我们这里使用bl,是相对跳转,我们必须认识到一个问题,此时我们的sdram虽然初始化好了,但是此刻我们sdram里面是没有程序的,需要先进行重定位,把nor flash的内容全部copy到sdram,所以此时(还没有拷贝的时候) copy2sdram是在nor flash里面执行的,那么使用bl也就可以理解了。但是clean_bss这个函数,到底应不应该使用bl呢?似乎好像我们完成了重定位,让text段,rodata段,data段都重定位到了sdram,可是,sdram这上面几个段之后才开始存放bss段,而bss段的变量是为0值得,不会放在bin文件中,如果这里不使用bl clean_bss,而使用 ldr pc,=clean_bss绝对跳转,程序会卡死。

回到C语言引用连接脚本的方法:

参考连接(请点击)

在编译阶段,会有一个叫做符号表的东西,

技术分享图片

c程序中不保存lds中的变量,但是万一c程序需要使用lds的文件,就可以通过编译程序时的符号表来引用。

上图已经显示了,C语言是变量名,然后变量地址,而连接脚本lds中,是符号名,然后它的值。

现在,我们这样对比,我们在C语言中要取一个变量的地址,是使用 &符号,就得到符号表中对应的地址了,

同样的道理,在c中引用连接脚本的符号,我们需要的是lds符号的值,也还是通过 &符号,只不过,此时取地址符 & +lds的符号,得到的是符号的值,而不是符号本身的地址了,而这符号的值,却又恰好是某个地址。(请仔细体会这个对比)

所以,我们上面采用外部声明变量的方式。

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

b. 使用时, 要取址, 比如:
int *p = &abc; // p的值即为lds文件中abc的值

声明的类型可以是int也可以char。此时类型不重要,但是,最好是声明成你想使用的那种类型。

技术分享图片

这是官方的参考,所以具体声明成什么类型,虽然不影响,但是最好是声明成你想使用的类型。因为在符号表中,连接脚本的符号表是符号和值,直接存储了,没有再开辟地址,在C语言使用extern声明之前,lds中的符号已经被定义在符号表中了,也就意味着,char或int类型修饰对符号的值没有影响,该值早就在符号表确定了,而我们C语言中之所以要声明一个类型,是为了方便后面要使用lds中这个符号的操作,而且C语言语法也要求标识符必须要有类型修饰。

对lds中的符号取地址,得到就是这个符号的值,而这个值,正好代表了某个地址。

C语言引用连接脚本lds中的符号——清除bss段,c实现方式

标签:ram   理解   启动   ali   img   引用   使用   文件   unsigned   

原文地址:http://www.cnblogs.com/yangguang-it/p/8068088.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!