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

先看连接脚本:

SECTIONS
{
. = 0x30000000; __code_start = .; . = ALIGN();
.text :
{
*(.text)
} . = ALIGN();
.rodata : { *(.rodata) } . = ALIGN();
.data : { *(.data) } . = ALIGN();
__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 *); 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++ = ;
}
}

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绝对跳转,程序没有输出,因为此时没有保存lr寄存器的值。

但是,如果非要使用ldr绝对跳转呢?可以这样,增加一个标号:

     ldr pc,=m

m:
bl clean_bss
bl main /* 绝对跳转, 跳到SDRAM */

增加标号m,绝对跳转到m处执行,这个时候程序运行于sdram了,后面使用bl指令即可。

为什么想要这样呢?

严格来说,重定位完毕,我们的程序就可以在sdram中运行了,而我们之前的程序采用

bl clean_bss

ldr pc,=main

这样会导致清除bss段的代码还是运行于nor flash上,而并非出于sdram上,所以我们采用绝对跳转的方式。清除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实现方式的更多相关文章

  1. gcc连接脚本lds详解

    转载:blog.chinaunix.net/uid-28685940-id-3889918.html 我们对每个c或者汇编文件进行单独编译,但是不去连接,生成很多.o 的文件,这些.o文件首先是分散的 ...

  2. C语言引用另一个源文件中定义的数组

    C语言中是可以引用另外一个源文件的全局数组的,但是不能引用局部数组. 引用方式举例如下: 设a.c文件有有数据定义 int  array1[10]; 现有b.c文件中想访问a.c中的array1数组 ...

  3. 第2阶段——编写uboot之硬件初始化和制作链接脚本lds(1)

    目标: 1.关看门狗 2.设置时钟 3.初始化SDRAM (初始化寄存器以及清除bss段) 4.重定位 (将nand/nor中代码COPY到链接地址上,需要初始化nandflash,读flash) 5 ...

  4. 嵌入式Linux-linux连接脚本

    嵌入式Linux-linux连接脚本 介绍 每一个链接过程都由链接脚本(linker script, 一般以lds作为文件的后缀名)控制. 链接脚本主要用于规定如何把输入文件内的section放入输出 ...

  5. u-boot中bss段的使用

    近日在调试uboot时,发现了一个现象,即在relocate_code前如果给未初始化或者初始化值为0的变量赋值的话,则在relocate_code后程序无法正常执行.经过学习,恶补如下知识 BSS段 ...

  6. Linux的nm查看动态和静态库中的符号

    功能 列出.o .a .so中的符号信息,包括诸如符号的值,符号类型及符号名称等.所谓符号,通常指定义出的函数,全局变量等等. 使用 nm [option(s)] [file(s)] 有用的optio ...

  7. 让C#语言充当自身脚本!——.NET中的动态编译

    原文:让C#语言充当自身脚本!--.NET中的动态编译 代码的动态编译并执行是.NET平台提供给我们的很强大的一个工具,用以灵活扩展(当然是面对内部开发人员)复杂而无法估算的逻辑,并通过一些额外的代码 ...

  8. shell中引用其他脚本的方法

    在Shell中引用其他脚本的方法是source   filename.sh 或    .    filename.sh 注意:      .   和   filename.sh之间必须有空格

  9. C语言学习笔记 (002) - C++中引用和指针的区别(转载)

    下面用通俗易懂的话来概述一下: 指针-对于一个类型T,T*就是指向T的指针类型,也即一个T*类型的变量能够保存一个T对象的地址,而类型T是可以加一些限定词的,如const.volatile等等.见下图 ...

随机推荐

  1. LAMP环境搭建实现网站动静分离[转]

    目录: 1.环境概述 2.动静分离拓扑图 3.各服务器功能规划 4.各服务器基础环境配置 5.httpd安装配置 6.php安装配置及启用opcache加速功能 7.mysql安装配置 8.wordp ...

  2. 多级菜单系统安装维护shell脚本实现企业级案例

    演示效果: 1.一级菜单 2.二级菜单 3.执行操作 脚本参考: #!/bin/bash #author lic(oldboy linux student) #date 1304 DISK_NO=&q ...

  3. 树莓派UFW防火墙简单设置

    ufw是一个主机端的iptables类防火墙配置工具,比较容易上手.如果你有一台暴露在外网的树莓派,则可通过这个简单的配置提升安全性. 安装方法 sudo apt-get install ufw 当然 ...

  4. lineman 的理念与 modern web app

    无意中翻到javascript 有个 lineman工具, 提供了一些脚手架 以及 默认的app目录结构,同时还附带了诸多前端的性能优化工具,在他的主页还发现其理念与我之前关于web app的开发模型 ...

  5. Happy Java:定义泛型参数的方法

    在平时写代码时,可以自定义泛型类.当使用同一类型的对象时,这是非常有用的,但在实例化类之前,我们不知道它将是哪种类型. 下面让我们定义一个使用泛型参数的方法.首先,在定义一个类用到泛型时,必须使用特殊 ...

  6. PCM、G.729等常用VoIP编码的理论带宽计算

    可能通信背景的同学,一提到PCM编码,脑海里都能跳出来一个数值64K. 一.64KB还是64Kb? 64Kb! 二.哪里来的64Kb? CCITT规定抽样率为每秒8000KHz,每抽样值编8位码,所以 ...

  7. Git实战(二)原理

    上次的博文Git实战(一)版本号控制概述中我们简介了一下版本号控制系统的概念,重点对版本号控制的三种类型进行了分析和对照,从本篇博文開始我们进入Git的世界,首先介绍一下Git实现版本号控制的原理. ...

  8. 基础004_V7-DSP Slice

    主要参考ug479.pdf.之前的文章:FIR调用DSP48E_05.本文主要记录基本用法. 一.DSP48核 A-参数说明 instrctions,多个功能,通过sel选用 目前没发现C勾选与否,有 ...

  9. ms12_004漏洞进行渗透

    环境: 攻击机:kail linux (IP:192.168.31.54) 目标机:winds 7 (IP:192.168.31.136) 1.启动metaspolit 2.输入命令search ms ...

  10. 在Windows系统上怎么使用SecureCRT链接Linux AWS EC2 -摘自网络

    在Windows系统上就需要使用SecureCRT,Putty等工具,进行连接.但是AWS提供的XXX.pem文件,需要做一些处理SecureCRT的方法: 1.使用XXX.pem文件生成一个公钥文件 ...