4.1 C语言中的段

  编译器在编译程序的时候,将程序中的所有的元素分成了一些组成部分,各部分构成一个段,所以说段是可执行程序的组成部分。

  • 代码段:代码段就是程序中的可执行部分,直观理解代码段就是函数堆叠组成的。代码段由程序中的各个函数产生,函数的每一个语句将最终经过编译和汇编生成二进制机器代码(具体生成哪种体系结构的机器代码由编译器决定)。

    • 有些特殊数据会被放到代码段

      • C 语言中使用 char *p = "linux" ;定义字符串时,字符串"linux"实际被分配在代码段,也就是说这个"linux"字符串实际上是一个常量字符串而不是变量字符串。
      • const 型常量:C语言中const关键字用来定义常量,常量就是不能被改变的量。const的实现方法至少有2种: 
        • 第一种就是编译将 const 修饰的变量放在代码段去以实现不能修改(普遍见于各种单片机的编译器);
        • 第二种就是由编译器来检查以确保 const 型的常量不会被修改,实际上const 型的常量还是和普通变量一样放在数据段的(gcc中就是这样实现的)。   
  • 数据段(也被称为数据区、静态数据区、静态区):数据段就是程序中的数据,直观理解就是C语言程序中的全局变量。放在.data段的变量有2种:
    • 第一种是显式初始化为非零的全局变量。
    • 第二种是静态局部变量,也就是static修饰的局部变量。(普通局部变量分配在栈上,静态局部变量分配在.data段),未初始化或显式初始化为0的全局变量放在bss段
    • 显式初始化为非零的全局变量和静态局部变量放在数据段
    • 注意:全局变量才算是程序的数据,局部变量不算程序的数据,只能算是函数的数据
    • 数据段又分为 只读数据段(RO Data) 和 读写数据段(RW Data):
      • 只读数据段由程序中所使用的数据产生,该部分数据的特点是在运行中不需要改变,因此编译器会将该数据放入只读的部分中。C语言的一些语法将生成只读数据段。
      • 读写数据段表示了在目标文件中一部分可以读也可以写的数据区,在某些场合它们又被称为已初始化数据段。这部分数据段和代码段,与只读数据段一样都属于程序中的静态区域,但是具有可写的特点。
  • bss段(又叫ZI(zero initial)段):未初始化数据段(BSS), 未初始化数据段常被称之为BSS(英文Block Start by Symbol的缩写)。与读写数据段类似,它也属于静态数据区,但是该段中的数据没有经过初始化。因此它只会在目标文件中被标识,而不会真正称为目标文件中的一个段,该段将会在运行时产生。未初始化数据段只有在运行的初始化阶段才会产生,因此它的大小不会影响目标文件的大小。
    • 数据段(.data)和bss段的区别和联系:二者本来没有本质区别,都是用来存放C程序中的全局变量的。区别在于把显示初始化为非零的全局变量存在.data段中,而把显式初始化为0或者并未显式初始化(C语言规定未显式初始化的全局变量值默认为0)的全局变量存在bss段。
  • 内存四区:
    • 栈区(stack):由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
    • 堆区(heap): malloc
    • 数据区: 
      • 全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
      • 常量区 :常量字符串就是放在这里的。 程序结束后由系统释放
    • 代码区:存放函数体的二进制代码。      

4.2 链接脚本分析

  uboot的链接脚本和裸机中的链接脚本并没有本质区别,只是复杂度高一些,文件多一些,使用到的技巧多一些。

  脚本路径:u-boot-1.1.6\board\100ask24x0\u-boot.lds

 /* 输出格式为 elf32-littlearm, */
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
/* 输出架构为 ARM */
OUTPUT_ARCH(arm)
/* 用来指定整个程序的入口地址,所谓入口地址就是整个程序的开头地址,可以认为就是整个程序的第一句指令。有点像C语言中的main。 */
/* _start 就是汇编的起始函数 */
ENTRY(_start)
/* SECTIONS 就是整个链接脚本的指定 */
SECTIONS
{
/* 指定程序的链接地址有2种方法:一种是在Makefile中ld的flags用-Ttext 0x20000000来指定;
第二种是在链接脚本的SECTIONS开头用.=0x20000000来指定。
两种都可以实现相同效果。这两种技巧是可以共同配合使用的,也就是说既在链接脚本中指定也在ld flags中用-Ttext来指定。两个都指定以后以-Ttext指定的为准。
uboot的最终链接起始地址就是在Makefile中用-Ttext 来指定的,注意 TEXT_BASE 变量。最终来源是 Makefile 中配置对应的命令中,在make xxx_config时得到的。
若没有配置,则由此处指定*/
. = 0x00000000; . = ALIGN(); /* 4字节对齐 */
/* 代码段 */
/* 在代码段中,必须注意文件的排列顺序,这些顺序会影响编译的时候这些 .o 文件在生成的u-boot.bin 中的排列顺序 */
/* 指定必须放在前面部分的那些文件就是那些必须安排在前16KB内的文件,这些文件中的函数在前16KB会被调用。在后面第二部分(16KB之后)中调用的程序,前后顺序就无所谓了。 */
.text :
{
cpu/arm920t/start.o (.text)
board/100ask24x0/boot_init.o (.text)
*(.text) /* 剩下的所有的未指出名字的 .o */
} . = ALIGN();
/* 只读数据段 */
.rodata : { *(.rodata) } . = ALIGN();
/* 普通数据段 */
.data : { *(.data) } . = ALIGN();
/* 自定义段 */
.got : { *(.got) } . = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) } /* 自定义 u_boot 命令段 */
__u_boot_cmd_end = .; . = ALIGN();
__bss_start = .;
.bss : { *(.bss) } /* bss 段 */
_end = .;
}

  链接脚本中除了.text  .data .rodata .bss段等编译工具自带的段之外,编译工具还允许我们自定义段。譬如uboot总的.u_boot_cmd段就是自定义段。自定义段很重要。

四、u-boot 链接脚本的更多相关文章

  1. 裸板驱动总结(makefile+lds链接脚本+裸板调试)

    在裸板2440中,当我们使用nand启动时,2440会自动将前4k字节复制到内部sram中,如下图所示: 然而此时的SDRAM.nandflash的控制时序等都还没初始化,所以我们就只能使用前0~40 ...

  2. arm裸板驱动总结(makefile+lds链接脚本+裸板调试)

    在裸板2440中,当我们使用nand启动时,2440会自动将前4k字节复制到内部sram中,如下图所示: 然而此时的SDRAM.nandflash的控制时序等都还没初始化,所以我们就只能使用前0~40 ...

  3. GNU linker script,ld script,GNU链接脚本

    https://blog.csdn.net/itxiebo/article/details/50937412 https://blog.csdn.net/itxiebo/article/details ...

  4. [转]Linux下的lds链接脚本详解

    转载自:http://linux.chinaunix.net/techdoc/beginner/2009/08/12/1129972.shtml     一. 概论 每一个链接过程都由链接脚本(lin ...

  5. Linux下的lds链接脚本基础

    转载:http://soft.chinabyte.com/os/104/12255104.shtml   今天在看uboot引导Linux部分,发现要对链接脚本深入了解,才能知道各个目标文件的内存分布 ...

  6. Linux下的lds链接脚本简介

    转载:http://hubingforever.blog.163.com/blog/static/171040579201192472552886/   一. 概论 每一个链接过程都由链接脚本(lin ...

  7. Linker Scripts3--简单的链接脚本命令1

    1.前言 这个部分我们描述了简单的链接脚本命令 2.设置entry point 程序中第一条运行的指令被称为入口点entry point,可以使用ENTRY链接脚本命令设置entry point,参数 ...

  8. Linux链接脚本学习--lds

    一.概论 ld: GNU的链接器. 用来把一定量的目标文件跟档案文件链接在一起,并重新定位它们的数据,链接符号引用. 一般编译一个程序时,最后一步就是运行ld进行链接 每一个链接都被一个链接脚本所控制 ...

  9. [转]Linux下的链接脚本基础

    [转]http://linux.chinaunix.net/techdoc/beginner/2009/08/12/1129972.shtml 1. 前言 (1)每一个链接过程都由链接脚本(linke ...

随机推荐

  1. codeforces548B

    Mike and Fun CodeForces - 548B Mike and some bears are playing a game just for fun. Mike is the judg ...

  2. PKUWC 2019&WC 2019爆零记

    PKUWC 2019&WC 2019爆零记 毕竟过了很久了,杂七杂八的东西就不写了,并且除成绩之外的内容不保证其正确性. Day1 T1:看到这道题很舒服啊,枚举top序算合法图的数量,状压D ...

  3. Qt ------ 覆盖eventFilter(),捕获组件事件,事件处理

    在Qt中,当一个事件发生时(例如鼠标点击或某个键盘上的按键按下),其传递顺序如图所示.从这个图可以看出,事件过滤器首先获得事件,其次才是部件的 event 函数,最后是部件的事件处理函数 事件过滤器由 ...

  4. Luogu4221 WC2018州区划分(状压dp+FWT)

    合法条件为所有划分出的子图均不存在欧拉回路或不连通,也即至少存在一个度数为奇数的点或不连通.显然可以对每个点集预处理是否合法,然后就不用管这个奇怪的条件了. 考虑状压dp.设f[S]为S集合所有划分方 ...

  5. BZOJ5249 九省联考2018IIIDX(线段树+贪心)

    显然这形成了一个树形结构.考虑这样一种贪心:按照曲目顺序,每次取消其父亲的预留,并选择当前可选择(保证其子树有合法选择且满足预留)的最大值,然后对其子树预留出大于等于他的一些值.这个做法显然是正确的. ...

  6. Spring的编程式事务和声明式事务

    事务管理对于企业应用来说是至关重要的,当出现异常情况时,它也可以保证数据的一致性. Spring事务管理的两种方式 spring支持编程式事务管理和声明式事务管理两种方式. 编程式事务使用Transa ...

  7. 【BZOJ2484】[SDOI2011]打地鼠(暴力)

    [BZOJ2484][SDOI2011]打地鼠(暴力) 题面 BZOJ 洛谷 题解 看到数据范围这题就应该是一个暴力题了. 先考虑假如我们知道了锤子的大小\(R*C\),那么显然只需要从左上角开始从左 ...

  8. C# ADO.NET基础&实战

    什么是ADO.NET:数据库访问技术! 作用:通过程序来连接访问数据库! 一.基础: using System.Data.SqlClient;    //数据库连接命名空间 string connec ...

  9. (转)Java程序员的面试经历和题库

    背景:最近我在找工作,前期就像打了鸡血的一样,隔一段时间没有面试,就又松懈了下来,看到别人写的面经,感觉就像打脸一般,以后要多多总结前人的经验,时刻保持压力状态才是. 作者:nuaazhaofeng2 ...

  10. sizeof 与 字节对齐

    转:http://baike.baidu.com/view/1356720.htm sizeof是运算符,可用于任何变量名.类型名或常量值,当用于变量名(不是数组名)或常量时,它不需要用圆括号.    ...