文章目录
- 2.链接文件
- 2.0. 参考链接
- 2.1._stext 和 _etext
- 2.2. "."与"*符号作用
- 2.3.`.linkonce` 段
- 2.4. KEEP
- 2.5 ENTRY
- 2.6 PROVIDE
- 2.7 AT
- 2.8 SORT
- 2.9 NOLOAD
- 源文件路径:https://github.com/wdfk-prog/RT-Thread-Study
2.链接文件
2.0. 参考链接
https://home.cs.colorado.edu/~main/cs1300/doc/gnu/ld_toc.html
2.1._stext 和 _etext
- stext 和 _etext 符号通常用于表示内核代码段的开始和结束位置。
//定义了一个符号。这个符号的值等于当前的位置计数器(.),也就是 .text 段的起始地址。
_stext = .;
//定义了一个符号。这个符号的值等于当前的位置计数器(.),也就是 .text 段的结束地址。
_etext = .;
2.2. ".“与”*符号作用
SECTIONS
{
. = 0x10000;
.text :
{
*(.text)
}
. = 0x8000000;
.data :
{
*(.data)
}
.bss :
{
*(.bss)
}
}
- 第一行设置了特殊符号’.',这是位置计数器。如果您没有以其他方式指定输出部分的地址(稍后将描述其他方式),则从位置计数器的当前值设置该地址。然后,位置计数器按输出部分的大小递增。在“SECTIONS”命令的开头,位置计数器的值为“0”。
- ’ *‘是一个通配符,可以匹配任何文件名。表达式
*(.text)
表示所有’。所有输入文件中的文本输入节。
段名 | 存储属性 | 内存分配 |
---|---|---|
代码段 .text | 存放可执行程序的指令,存储态和运行态都有 | 静态 |
数据段 .data | 存放已初始化(非零初始化的全局变量和静态局部变量)的数据,存储态和运行态都有 | 静态 |
bss段 .bss | 存放未初始化(未初始化或者0初始化的全局变量和静态局部变量)的数据,存储态和运行态都有 | 静态 |
堆 heap | 动态分配内存,需要通过malloc手动申请,free手动释放,适合大块内存。容易造成内存泄漏和内存碎片。运行态才有。 | 动态 |
栈 stack | 存放函数局部变量和参数以及返回值,函数返回后,由操作系统立即回收。栈空间不大,使用不当容易栈溢出。运行态才有 | 静态 |
2.3..linkonce
段
https://ftp.gnu.org/old-gnu/Manuals/gas/html_node/as_102.html
.gnu.linkonce.t
是一个链接器区段,用于存放那些只需要链接一次的函数或者符号。区段名称后面通常跟着函数或者符号的名字。关于 linkonce
的概念,GCC文档给出的解释是:“某些情况下,编译器为了优化而生成的代码项,不必在每一个包含了相同代码的编译单元中都出现。编译器将这些代码项放在 .linkonce
区段中,链接器在链接时只保留一份。”
linkonce
区段有几种类型:
.gnu.linkonce.b.*
(用于未初始化的全局变量);.gnu.linkonce.d.*
(用于已初始化的全局变量);.gnu.linkonce.r.*
(用于常量数据);.gnu.linkonce.t.*
(用于文本,也就是可执行代码)等。
例如,如果你有一个函数 foo
,GCC可能将其编译]到 .gnu.linkonce.t.foo
区段中,如果链接时发现其它对象文件也有 .gnu.linkonce.t.foo
,那么链接器只会保留其中一份。这主要用于C++中的 inline
函数或模板函数,通常情况下,每一个使用到这些函数的源文件都会生成一份函数的实例,但是链接时只需要保留一份即可。这样可以减少目标文件的大小,提高链接效率。
2.4. KEEP
当使用链接标记不应该消除的部分。这可以通过在输入节的通配符项周围加上’ KEEP() '来实现不被优化
2.5 ENTRY
程序中执行的第一条指令称为入口点。使用 ENTRY
链接描述文件命令来设置入口点。
有几种方法可以设置入口点。链接器将依次尝试以下方法来设置入口点,当其中一个方法成功时停止:
- the `-e’ entry command-line option;
- the
ENTRY(symbol)
command in a linker script; - the value of the symbol
start
, if defined; - the address of the first byte of the
.text'
section, if present; - The address
0
.
2.6 PROVIDE
PROVIDE(__dtors_end__ = .);
- 只有在引用但未定义的情况下,才能使用提供
PROVIDE
关键字来定义符号;如果__dtors_end__
已经被定义,那么PROVIDE
语句将被忽略。这对于为某些符号提供默认值很有用。这在考虑构造函数和析构函数列表符号(如’ CTOR_LIST ')时尤为重要,因为这些符号通常被定义为通用符号。
2.7 AT
AT
关键字用于指定节(section)在内存中的加载地址。这个地址是物理地址,与链接地址(即节在输出文件中的位置)可能不同。
例如,在 .data : AT (_sidata)
这行代码中,.data
节将被加载到内存的 _sidata
地址处。这通常用于ROM到RAM的复制操作,其中 _sidata
是在ROM中存储的初始化数据的开始地址。
2.8 SORT
在链接脚本中,SORT的作用是对输入的部分进行排序。在你的代码中,SORT(.dtors.)和 (.dtors)被用来收集所有的析构函数(destructors)。
SORT(.dtors.*)会把所有以.dtors.开头的部分按照字母顺序排序。这在某些情况下是有用的,例如当你想要按照某种特定的顺序执行析构函数时。
- (.dtors)则会把所有以.dtors开头的部分收集起来,但不进行排序。
这两个指令通常一起使用,以确保所有的析构函数都被正确地收集和排序。在你的代码中,析构函数被放在__dtors_start__和__dtors_end__之间,这样在程序结束时,运行时系统就知道从哪里开始调用析构函数,以及在哪里结束。这是一种常见的在C++中管理全局和静态对象生命周期的方法
2.9 NOLOAD
.RxDecripSection
,.TxDecripSection
和.RxArraySection
都被设置为NOLOAD
,这意味着在程序执行时,它们不会被加载到内存中。这通常用于DMA操作,其中硬件需要知道数据的物理地址,而不是由MMU管理的虚拟地址。通常用于DMA配置,例如以太网