【ARM 嵌入式 编译系列 7.1 -- GCC 链接脚本中节区及各个段的详细介绍】
文章目录
- 什么是Section(节区)
- 输入文件常见节区有哪些?
- 什么是 glue code?.glue_7和.glue_7的作用是什么?
- 链接脚本中的 KEEP 关键字是什么呢作用?
- 链接脚本中的 PROVIDE 关键字是什么呢作用?
上篇文章:ARM 嵌入式 编译系列 7 – ARM GCC 链接脚本详细讲解
下篇文章:ARM 嵌入式 番外篇 编译系列 8 – RT-Thread 编译命令 Scons 详细讲解
什么是Section(节区)
在编程语言中,节区(Section)是对程序的一个逻辑分割,它包含了程序中特定类型的信息。一个完整的程序通常会被分割成几个节区,比如代码节区(.text)、数据节区(.data)和 BSS 节区(.bss)等。
在 GCC 链接脚本中,你可以使用 SECTIONS
命令来定义输出文件中各个节区的位置和顺序。其中,每个节区都用花括号 {}
括起来,并且可以包含多个输入节区和符号。
以下是一个简单的例子:
SECTIONS
{ .text : { *(.text) } > FLASH .data : { *(.data) } > RAM .bss : { *(.bss) } > RAM
}
在这个示例中,.text
、.data
和 .bss
是输出文件中的节区,而 *(.text)
、*(.data)
和 *(.bss)
是输入文件中的节区。> FLASH
和 > RAM
指定了节区应该被放置到哪个内存区域。
需要注意的是,链接器会按照 SECTIONS
命令中节区的顺序来布局输出文件中的节区。所以,如果你需要特定节区在内存中的位置或顺序,请在 SECTIONS 命令中进行指定。
输入文件常见节区有哪些?
在 ARM GCC 链接脚本中,常见的输入文件节区主要包括以下几种:
-
.text
:存放代码的节区,通常对应 FLASH 等只读存储区; -
.rodata
:存放只读数据的节区,比如常量字符串、const 声明的变量等,也通常对应 FLASH 等只读存储区; -
.data
:存放已初始化的全局变量和静态变量的节区。此节区的初始化值存储在 FLASH 中,但在程序启动时会被复制到 RAM 中; -
.bss
:存放未初始化的全局变量和静态变量的节区。此节区不占用 FLASH 空间,仅在 RAM 中预留空间; -
.heap
:堆区,用于动态内存分配,如malloc
、free
等; -
.stack
:栈区,用于存放局部变量和函数调用的上下文; -
.isr_vector
:这个节区通常用于存放中断向量表。对于基于 ARM Cortex-M 的微控制器,中断向量表包括了复位向量、异常处理函数和中断处理函数的入口地址等。在程序启动时,CPU 会加载中断向量表到特定的地址,并在中断发生时通过中断向量表跳转到相应的处理函数; -
.init
:这个节区包含了程序的初始化代码。在 C 程序中,全局变量和静态变量的初始化代码通常就在这个节区。此外,如果程序使用了 C++,那么全局对象的构造函数也会被放到这个节区; -
.fini
:这个节区包含了程序的终止代码。在 C 程序中,这个节区通常为空。但如果程序使用了 C++,那么全局对象的析构函数会被放到这个节区。
这些节区在链接脚本中的定义和布局将决定了它们在内存中的位置和大小。并且这些节区的布局需要与 MCU 的内存布局匹配,以确保代码和数据能够被正确地加载和执行。
实际使用的链接脚本中内容设置比较多,如下:
SECTIONS
{.text :{. = ALIGN(4);_stext = .;KEEP(*(.isr_vector)) /* Startup code */. = ALIGN(4);*(.text) /* remaining code */*(.text.*) /* remaining code */*(.rodata) /* read-only data (constants) */*(.rodata*)*(.glue_7)*(.glue_7t)*(.gnu.linkonce.t*)/* section information for finsh shell */. = ALIGN(4);__fsymtab_start = .;KEEP(*(FSymTab))__fsymtab_end = .;. = ALIGN(4);__vsymtab_start = .;KEEP(*(VSymTab))__vsymtab_end = .;/* section information for initial. */. = ALIGN(4);__rt_init_start = .;KEEP(*(SORT(.rti_fn*)))__rt_init_end = .;. = ALIGN(4);PROVIDE(__ctors_start__ = .);KEEP (*(SORT(.init_array.*)))KEEP (*(.init_array))...
什么是 glue code?.glue_7和.glue_7的作用是什么?
GCC 编译器会自动生成一些代码来处理 ARM 和 Thumb 指令集之间的交互,这些代码通常被称为 “glue code”。在链接脚本中,这些 glue code 通常被放在 .glue_7
和 .glue_7
节区中。
.glue_7
节区包含了从 ARM 模式到 Thumb 模式的跳转代码;.glue_7t
节区包含了从 Thumb 模式到 ARM 模式的跳转代码。
这些节区中的代码通常会被自动插入到需要进行模式转换的地方。
在链接脚本中,你通常需要将这两个节区放到 .text 节区中,例如:
SECTIONS
{ .text : { *(.text) *(.glue_7) *(.glue_7t) } > FLASH
}
在这个示例中,.glue_7
和 .glue_7t
节区被放置在 .text
节区中,这样它们就会被加载到 FLASH 中,并能在程序运行时被执行。
注意 只有在混合使用 ARM 和 Thumb 指令集的情况下,编译器才会生成 glue code。如果你的程序只使用一种指令集,那么就不需要关心这两个节区。
链接脚本中的 KEEP 关键字是什么呢作用?
在 GCC 链接脚本中,KEEP 关键字用于防止某些节区在链接过程中被丢弃。
在链接过程中,如果链接器发现某些节区没有被引用,链接器可能会选择丢弃这些节区以节省空间。但是有些时候,你可能需要保留这些节区,即使它们没有被直接引用。这时,你就可以使用 KEEP 关键字。
KEEP 关键字的语法如下:
KEEP(file section)
file
是输入的文件列表,可以使用通配符。
section
是文件中需要保留的节区列表,也可以使用通配符。
比如说,以下的链接脚本会保留所有输入文件中的 .init
和 .fini
节区:
SECTIONS
{ .init : { KEEP(*(.init)) } > FLASH .fini : { KEEP(*(.fini)) } > FLASH
}
在这个示例中,KEEP(*(.init))
和 KEEP(*(.fini))
分别会保留所有输入文件中的 .init
和 .fini
节区,这些节区在链接过程中不会被丢弃。
链接脚本中的 PROVIDE 关键字是什么呢作用?
见文章:ARM 嵌入式 编译系列 7 – ARM GCC 链接脚本详细讲解
链接脚本中定义了 FSymTab
,VSymTab
及 .rti_fn
这几个节区,以 .rti_fn
为例,在代码中有很多初始化函数需要按照先后顺序进行执行,编译的时候会统一将这些初始化函数放到某一个节区中,比如 .rti_fn
节区。如下代码是将函数 fn
放到 .rti_fn
节区中,然后根据 level
的值进行排序。
#if RT_DEBUG_INITstruct rt_init_desc{const char* fn_name;const init_fn_t fn;};#define INIT_EXPORT(fn, level) \const char __rti_##fn##_name[] = #fn; \RT_USED const struct rt_init_desc __rt_init_desc_##fn RT_SECTION(".rti_fn." level) = \{ __rti_##fn##_name, fn};#else#define INIT_EXPORT(fn, level) \RT_USED const init_fn_t __rt_init_##fn RT_SECTION(".rti_fn." level) = fn#endif
在 rt-thread/include/rtdef.h
中实现了如下宏定义来定义初始化函数的执行先后顺序。
/* board init routines will be called in board_init() function */
#define INIT_BOARD_EXPORT(fn) INIT_EXPORT(fn, "1")/* pre/device/component/env/app init routines will be called in init_thread */
/* components pre-initialization (pure software initilization) */
#define INIT_PREV_EXPORT(fn) INIT_EXPORT(fn, "2")
/* device initialization */
#define INIT_DEVICE_EXPORT(fn) INIT_EXPORT(fn, "3")
/* components initialization (dfs, lwip, ...) */
#define INIT_COMPONENT_EXPORT(fn) INIT_EXPORT(fn, "4")
/* environment initialization (mount disk, ...) */
#define INIT_ENV_EXPORT(fn) INIT_EXPORT(fn, "5")
/* appliation initialization (rtgui application etc ...) */
#define INIT_APP_EXPORT(fn)
上篇文章:ARM 嵌入式 编译系列 7 – ARM GCC 链接脚本详细讲解
下篇文章:ARM 嵌入式 番外篇 编译系列 8 – RT-Thread 编译命令 Scons 详细讲解
相关文章:
【ARM 嵌入式 编译系列 7.1 -- GCC 链接脚本中节区及各个段的详细介绍】
文章目录 什么是Section(节区)输入文件常见节区有哪些?什么是 glue code?.glue_7和.glue_7的作用是什么?链接脚本中的 KEEP 关键字是什么呢作用?链接脚本中的 PROVIDE 关键字是什么呢作用? 上篇文章:ARM 嵌…...

一文读懂HTML
文章目录 HTML的历史HTML的作用HTML的基本语言 HTML的历史 HTML(HyperText Markup Language)的历史可以追溯到20世纪90年代早期,它是互联网发展的重要里程碑之一。以下是HTML的历史概述: 早期阶段(1980年代末 - 1990年…...

MOCK测试
介绍 mock:就是对于一些难以构造的对象,使用虚拟的技术来实现测试的过程。 mock测试:在测试过程中,对于某些不容易构造或者不容易获取的对象,可以用一个虚拟的对象来代替的测试方 法。 接口Mock测试:在接口…...

Flutter源码分析笔记:Widget类源码分析
Flutter源码分析笔记 Widget类源码分析 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at: https://jclee95.blog.csdn.netEmail: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263/article/details/132259681 【介绍】&#x…...

PyTorch 微调终极指南:第 2 部分 — 提高模型准确性
一、说明 如今,在训练深度学习模型时,通过在自己的数据上微调预训练模型来迁移学习已成为首选方法。通过微调这些模型,我们可以利用他们的专业知识并使其适应我们的特定任务,从而节省宝贵的时间和计算资源。本文分为四个部分&…...

MySQL数据库----------安装anaconda---------python与数据库的链接
作者前言 🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂 🎂 作者介绍: 🎂🎂 🎂 🎉🎉🎉…...
nuxt页面布局
nuxt页面默认布局文件在layouts目录下default.vue,可将页面的头部和脚部提取出来,形成布局页,将主内容区域的内容替换成<nuxt />。附default.vue代码: <template><div class"app-container"><div…...
mac编译ffmpeg
- code: git clone https://git.ffmpeg.org/gitweb/ffmpeg.git - 编译安装 https://trac.ffmpeg.org/wiki/CompilationGuide - 使用homebrew安装dependency brew install automake fdk-aac git lame libass libtool libvorbis libvpx \ opus sdl shtool texi2ht…...

如何让你的图片服务也有类似OSS的图片处理功能
原文链接 前言 有自己机房的公司一般都有一套存储系统用于存储公司的图片、视频、音频、文件等数据,常见的存储系统有以NAS、FASTDFS为代表的传统文件存储,和以Minio为代表的对象存储系统,随着云服务的兴起很多公司逐渐将数据迁移到以阿里云…...
Oracle PL/SQL 类型(Type):索引表、嵌套表、变长数组、pipelined 管道
1、Oracle 新建员工表和部门表.sql。 集合类型 1、Oracle 集合是相同类型元素的组合,在集合中,使用唯一的下标来标识其中的每个元素,与 Java 的 List 很像。 2、常用集合方式: 类型语法下标元素个数初始值.extend能否存在DB中…...

Web 服务器 -【Tomcat】的简单学习
Tomcat1 简介1.1 什么是Web服务器 2 基本使用2.1 下载2.2 安装2.3 卸载2.4 启动2.5 关闭2.6 配置2.7 部署 3 Maven创建Web项目3.1 Web项目结构3.2 创建Maven Web项目 4 IDEA使用Tomcat4.1 集成本地Tomcat4.2 Tomcat Maven插件 Tomcat 1 简介 1.1 什么是Web服务器 Web服务器是…...

armbian使用1panel快速部署部署springBoot项目后端
文章目录 前言环境准备实现步骤第一步:Armbian安装1panel第二步:安装数据库第三步:查看数据库容器重要信息【重要】查看容器所在的网络查看容器连接地址 第四步:项目配置和打包第五步:构建项目镜像 前言 这里只是简单记录部署spr…...

Streamlit 讲解专栏(八):图像、音频与视频魔法
文章目录 1 前言2 st.image:嵌入图像内容2.1 图像展示与描述2.2 调整图像尺寸2.3 使用本地文件或URL 3 st.audio:嵌入音频内容3.1 播放音频文件3.2 生成音频数据播放 4 st.video:嵌入视频内容4.1 播放视频文件4.2 嵌入在线视频 5 结语&#x…...

python使用装饰器记录方法耗时
思路 python使用修饰器记录方法耗时,目的是每当方法执行完后,可以记录该方法耗时,而不需要在每个方法的执行前后,去创建一个临时变量,来记录耗时。 方式一(不推荐): 在每个方法的…...

JavaWeb课程学习--Day01
HTML 建立css文件: css使用方式: <span>...</span>无语意包裹标签 css中的三种选择器: 注意:播放视音频时要留出播放空间 盒子模型: 表格标签: 以上表格: 表单标签: 表…...
Spring Boot单元测试使用MockBean注解向Service注入Mock对象
1. 背景介绍 我们在测试时有一个Service,我们需要测试Service,但Service内部依赖ServiceA、ServiceB,此时我们希望Mock ServiceA,ServiceB 注入真实对象。 class Service {private ServiceA A;private ServiceB B;public int me…...
Java中使用instanceof判断对象类型
记录:470 场景:Java中使用instanceof判断对象类型。例如在解析JSON字符串转换为指定类型时,先判断类型,再定向转换。在List<Object>中遍历Object时,先判断类型,再定向转换。 版本:JDK 1…...

postman测试后端增删改查
目录 一、本文介绍 二、准备工作 (一)新建测试 (二)默认url路径查看方法 三、增删改查 (一)查询全部 (二)增加数据 (三)删除数据 (四&…...

根据源码,模拟实现 RabbitMQ - 通过 SQLite + MyBatis 设计数据库(2)
目录 一、数据库设计 1.1、数据库选择 1.2、环境配置 1.3、建库建表接口实现 1.4、封装数据库操作 1.5、针对 DataBaseManager 进行单元测试 一、数据库设计 1.1、数据库选择 MySQL 是我们最熟悉的数据库,但是这里我们选择使用 SQLite,原因如下&am…...
1、基于 CentOS 7 构建 LVS-DR 群集。 2、配置nginx负载均衡
一、基于CentOS7和、构建LVS-DR群集 准备四台虚拟机 ip作用192.168.27.150客户端192.168.27.151LVS192.168.27.152RS192.168.27.152RS 关闭防火墙 [rootlocalhost ~]# systemctl stop firewalld安装ifconfig yum install net-tools.x86_64 -y1、DS上 1.1 配置LVS虚拟IP …...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...