rtthread学习笔记系列(2) -- 宏

文章目录

  • 2.链接文件

    • [2.0. 参考链接](#2.0. 参考链接)
    • [2.1._stext 和 _etext](#2.1._stext 和 _etext)
    • [2.2. "."与"*符号作用](#2.2. "."与"*符号作用)
    • [2.3.`.linkonce` 段](#2.3..linkonce 段)
    • [2.4. KEEP](#2.4. KEEP)
    • [2.5 ENTRY](#2.5 ENTRY)
    • [2.6 PROVIDE](#2.6 PROVIDE)
    • [2.7 AT](#2.7 AT)
    • [2.8 SORT](#2.8 SORT)
    • [2.9 NOLOAD](#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 符号通常用于表示内核代码段的开始和结束位置。
c 复制代码
//定义了一个符号。这个符号的值等于当前的位置计数器(.),也就是 .text 段的起始地址。
_stext = .;
//定义了一个符号。这个符号的值等于当前的位置计数器(.),也就是 .text 段的结束地址。
_etext = .;

2.2. "."与"*符号作用

c 复制代码
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

assembly 复制代码
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配置,例如以太网
相关推荐
孤寂大仙v1 小时前
【Linux笔记】理解文件系统(上)
linux·运维·笔记
ianozo1 小时前
数据结构--【栈与队列】笔记
数据结构·笔记
极客BIM工作室2 小时前
机器学校的考试风波:误差分析、过拟合和欠拟合
笔记·机器学习
flashier3 小时前
C语言 进阶指针学习笔记
c语言·笔记·学习
大白的编程日记.3 小时前
【Linux学习笔记】Linux基本指令分析和权限的概念
linux·笔记·学习
螺旋式上升abc3 小时前
GO语言学习笔记
笔记·学习·golang
W起名有点难3 小时前
前端学习——CSS
前端·css·学习
Moonnnn.4 小时前
51单片机——汇编工程建立、仿真、调试全过程
汇编·笔记·嵌入式硬件·学习·51单片机
画个逗号给明天"4 小时前
TinyWebServer项目笔记——02 半同步半反应堆线程池
笔记
不会聊天真君6475 小时前
HTML5(Web前端开发笔记第一期)
笔记·html5