当前位置: 首页 > news >正文

A Sample Linker Script

原文地址:http://hertaville.com/2012/06/29/a-sample-linker-script/

 

A sample script file that will work with C based projects is provided below:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/******************************************************************************
  * This linker file was developed by Hussam Al-Hertani. Please use freely as 
  * long as you leave this header in place. The author is not responsible for any 
  * damage or liability that this file might cause.
******************************************************************************/
  
/* Entry Point */
ENTRY(Reset_Handler)
  
/* Specify the memory areas */
MEMORY
{
   FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 0x10000 /*64K*/
   RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 0x02000 /*8K*/
}
  
/* define stack size and heap size here */
stack_size = 1024;
heap_size = 256; 
  
/* define beginning and ending of stack */
_stack_start = ORIGIN(RAM)+LENGTH(RAM);
_stack_end = _stack_start - stack_size;
  
/* Define output sections */
SECTIONS
{
   /* The startup code goes first into FLASH */
   .isr_vector :
   {
     . = ALIGN(4);
     KEEP(*(.isr_vector)) /* Startup code */
     . = ALIGN(4);
   } >FLASH
  
   /* The program code and other data goes into FLASH */
   .text :
   {
     . = ALIGN(4);
     *(.text)           /* .text sections (code) */
     *(.text*)          /* .text* sections (code) */
     *(.rodata)         /* .rodata sections (constants, strings, etc.) */
     *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
     *(.glue_7)         /* glue arm to thumb code */
     *(.glue_7t)        /* glue thumb to arm code */
     . = ALIGN(4);
     _etext = .;        /* define a global symbols at end of code */
   } >FLASH
  
    .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
     .ARM : {
     __exidx_start = .;
       *(.ARM.exidx*)
       __exidx_end = .;
     } >FLASH
  
   /* used by the startup to initialize data */
   _sidata = .;
  
   /* Initialized data sections goes into RAM, load LMA copy after code */
   .data : AT ( _sidata )
   {
     . = ALIGN(4);
     _sdata = .;        /* create a global symbol at data start */
     *(.data)           /* .data sections */
     *(.data*)          /* .data* sections */
  
     . = ALIGN(4);
     _edata = .;        /* define a global symbol at data end */
   } >RAM
  
   /* Uninitialized data section */
   . = ALIGN(4);
   .bss :
   {
     /*  Used by the startup in order to initialize the .bss secion */
     _sbss = .;         /* define a global symbol at bss start */
     __bss_start__ = _sbss;
     *(.bss)
     *(.bss*)
     *(COMMON)
  
     . = ALIGN(4);
     _ebss = .;         /* define a global symbol at bss end */
     __bss_end__ = _ebss;
   } >RAM
  
     . = ALIGN(4);
     .heap :
     {
         _heap_start = .;
         . = . + heap_size;
     } > RAM
  
     . = ALIGN(4);
     . = _stack_end;
     .stack :
     {
         . = . + stack_size;
     } > RAM
  
     /* Remove information from the standard libraries */
     /DISCARD/ :
     {
         libc.a ( * )
         libm.a ( * )
         libgcc.a ( * )
     }
  
     .ARM.attributes 0 : { *(.ARM.attributes) }
}

The Linker script is somewhat self documenting. I will briefly go through the various sections. The first line of the linker script is:

?
1
ENTRY(Reset_Handler)

This defines the entry point into the chip. On exit from a reset condition, the first thing that the MCU executes is a reset handler function that initializes the chip and puts it in a known state. To view this handler (interrupt subroutine (ISR)) function take a look at the startup file.

The linker script then defines the sections of the memory map that in to which it will map the various sections of the object files. It does this in “Memory” section.

?
1
2
3
4
5
6
/* Specify the memory areas */
MEMORY
{
   FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 0x10000 /*64K*/
   RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 0x02000 /*8K*/
}

The memory map of the STM32F051C8 chip is shown in Page 35 of the datasheet . It shows that the Flash memory section starts at address 0×08000000 and is 64KB long or 65536 bytes long which in hex is 0×10000. The RAM memory section starts a address 0×20000000 and is 8KB long or 8192 bytes long, which in hex is 0×02000 . All of this information is provided to the linker via the memory section of the linker script. Also note the the FLASH memory s defined as (rx) which means that it has read and execute only, whereas the RAM memory is defined as (xrw) which means that it is read, write and execute.

The next major section of the linker script is called “SECTIONS”. It defines where each if the various sections of the object files goes into the memory map defined in the MEMORY section.

The first section defined under SECTIONS is the .isr_vector section. This section contains the interrupt vector table and the startup / initialization code i.e. the body of the Reset handler routine specified as the entry point. This is put first in flash memory starting at 0×08000000 as specified by the “>FLASH” found at the end of the section.

?
1
2
3
4
5
6
7
8
9
10
/* Define output sections */
SECTIONS
{
   /* The startup code goes first into FLASH */
   .isr_vector :
   {
     . = ALIGN(4);
     KEEP(*(.isr_vector)) /* Startup code */
     . = ALIGN(4);
   } >FLASH

The ALIGN(4) instructions tells the linker that this section ought to be word aligned. Since this is a 32-bit machine it typically needs to be word aligned (32-bit -> 4 bytes hence the ’4′ specified with the align command. )

?
1
2
3
4
5
6
7
8
9
10
11
12
13
/* The program code and other data goes into FLASH */
   .text :
   {
     . = ALIGN(4);
     *(.text)           /* .text sections (code) */
     *(.text*)          /* .text* sections (code) */
     *(.rodata)         /* .rodata sections (constants, strings, etc.) */
     *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
     *(.glue_7)         /* glue arm to thumb code */
     *(.glue_7t)        /* glue thumb to arm code */
     . = ALIGN(4);
     _etext = .;        /* define a global symbols at end of code */
   } >FLASH

The next section of the linker script is the .text section. This section includes all the .text sections from the object files. These .text sections contain all the binary instructions that our c and assembly programs were compiled/assembled into and are typically put in program memory, which in this case is flash. Notice that this section also contains .rodata sections which signifies that right after the linker has put the binary instructions into the program memory, it should but the constant data in their as well. At this point in time I’m not quite sure of the .glue_7 sections but I think they have to do with backwards compatibility between arm and thumb instructions. They are probably not needed. ofcourse this entire section .text section is put in Flash via the “>FLASH” linker instruction.

?
1
2
3
4
5
6
.ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
     .ARM : {
     __exidx_start = .;
       *(.ARM.exidx*)
       __exidx_end = .;
     } >FLASH

The following .ARM.extab section has to do with table/loop unwinding. I have found little information on it. I have included it here even though I know that I probably do not need it.

?
1
2
3
4
5
6
7
8
9
10
11
/* Initialized data sections goes into RAM, load LMA copy after code */
   .data : AT ( _sidata )
   {
     . = ALIGN(4);
     _sdata = .;        /* create a global symbol at data start */
     *(.data)           /* .data sections */
     *(.data*)          /* .data* sections */
  
     . = ALIGN(4);
     _edata = .;        /* define a global symbol at data end */
   } >RAM

The .data section contains all initialized global and static variables. the “AT” basically means that this code will be put in both (via LMA initializer) Flash and RAM. To explain this further the static and global variables of the .data section need to be stored in two different locations:

  • VMA (virtual memory address): the run-time address where the compiled code expects the variables to be. This will be in RAM as signified by “>RAM”.
  • LMA (load memory address): the addresses to which the initialization data are stored by the linker. This will be in Flash as signified by the “AT”.

The startup code will copy from .data section’s LMA to .data section’s  VMA.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* Uninitialized data section */
   . = ALIGN(4);
   .bss :
   {
     /*  Used by the startup in order to initialize the .bss secion */
     _sbss = .;         /* define a global symbol at bss start */
     __bss_start__ = _sbss;
     *(.bss)
     *(.bss*)
     *(COMMON)
  
     . = ALIGN(4);
     _ebss = .;         /* define a global symbol at bss end */
     __bss_end__ = _ebss;
   } >RAM

The next section of the linker script is the .bss section. The .bss section consists of uninitialized static and global variables. This section is saved in RAM.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
. = ALIGN(4);
.heap :
{
     _heap_start = .;
     . = . + heap_size;
} > RAM
 
. = ALIGN(4);
. = _stack_end;
.stack :
{
     . = . + stack_size;
} > RAM

The next two sections define the heap and stack sections of RAM. The heap starts right after the bss section and continues on until the heap size specified by the heap_size variable at the beginning of the script. With the exception of the stack section, all other sections grow upwards. the stack section is the only one that grows downwards. This basically means that the stack starts at the last location in the RAM which is 0×20002000 and grows downwards from their via the “stack_size” variable. Both the “stack_size” and the “heap_size” variables control the sizes of the stack and heap respectively. They must be sized such that both sections never overlap i.e. the sum of the two variables and the sizes of the data(VMA) and bss sections, must never be larger than the 8192.

Because the linker needs to specify memory sections in an upwards / growing fashion, we used the _stack_begin label, which basically is assigned to the address 0×20002000 and the stack size to determine the value of the _stack_end variable in the top of the script. This is used to decide where the stack section starts from the perspective of the linker.

Figure 1 represents the linker file rules graphically and demonstrates how the various sections are mapped into the Flash and RAM memories. The labels such as _etext, _sdata, _edata e.t.c define the begin and/or end addresses for each section.

 

Figure 1. Graphical representation of the rules defined in the linker file

 

The final sections ensure that no redundant code from the standard libraries is included into memory. I do not know the purpose of the “.ARM.attributes 0″ line either. The linker files would very likely function just fine without, but I will keep them for the time being.

?
1
2
3
4
5
6
7
8
9
10
     /* Remove information from the standard libraries */
     /DISCARD/ :
     {
         libc.a ( * )
         libm.a ( * )
         libgcc.a ( * )
     }
  
     .ARM.attributes 0 : { *(.ARM.attributes) }
}

This concludes our explanation of (most of) the linker file sections and its structure.

 

相关文章:

  • Load-time relocation of shared libraries
  • Position Independent Code (PIC) in shared libraries
  • Position Independent Code (PIC) in shared libraries on x64
  • getchar()函数的思考与总结
  • sturct stat 结构体中 st_mode 的含义
  • 环境变量及其函数
  • BIOS和DOS建立的中断向量表
  • CMOS RAM 各字节的含义
  • ubuntu命令行方式启动
  • 收集的一些句子
  • 从头开始编写操作系统
  • ubuntu源码级安装bochs
  • Linux下创建虚拟软盘镜像
  • c51软复位,实在经典,分析实在透彻
  • 51中ret和reti的区别
  • 分享一款快速APP功能测试工具
  • 《Java编程思想》读书笔记-对象导论
  • Docker 笔记(2):Dockerfile
  • Hexo+码云+git快速搭建免费的静态Blog
  • HTTP中GET与POST的区别 99%的错误认识
  • Js基础知识(一) - 变量
  • scala基础语法(二)
  • SegmentFault 技术周刊 Vol.27 - Git 学习宝典:程序员走江湖必备
  • 搭建gitbook 和 访问权限认证
  • 好的网址,关于.net 4.0 ,vs 2010
  • 前言-如何学习区块链
  • 区块链技术特点之去中心化特性
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 世界上最简单的无等待算法(getAndIncrement)
  • 微信公众号开发小记——5.python微信红包
  • 我从编程教室毕业
  • 学习JavaScript数据结构与算法 — 树
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 用简单代码看卷积组块发展
  • 由插件封装引出的一丢丢思考
  • 国内唯一,阿里云入选全球区块链云服务报告,领先AWS、Google ...
  • ​flutter 代码混淆
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • (第一天)包装对象、作用域、创建对象
  • (转载)虚函数剖析
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现
  • .net mvc 获取url中controller和action
  • .NET 的静态构造函数是否线程安全?答案是肯定的!
  • .net解析传过来的xml_DOM4J解析XML文件
  • .NET中的Exception处理(C#)
  • @ModelAttribute 注解
  • [ C++ ] STL_vector -- 迭代器失效问题
  • [ 数据结构 - C++] AVL树原理及实现
  • [ 隧道技术 ] 反弹shell的集中常见方式(二)bash反弹shell
  • [【JSON2WEB】 13 基于REST2SQL 和 Amis 的 SQL 查询分析器
  • [20171101]rman to destination.txt