ARM 链接器优化功能介绍
消除公共部分组
链接器可以检测节组的多个副本,并丢弃其他副本。
® Arm Compiler for Embedded 生成用于链接的完整对象。因此:
- 如果 C 和 C++ 源代码中存在内联函数,则每个对象都包含该对象所需的内联函数的外联副本。
- 如果在 C++ 源代码中使用模板,则每个对象都包含对象所需的模板函数。
在公共头文件中声明这些函数时,这些函数可能会在随后链接在一起的单独对象中多次定义。为了消除重复项,编译器将这些函数编译为公共节组的单独实例。
公共节组的单独实例可能不相同。例如,某些副本可能位于使用不同但兼容的构建选项、不同的优化或调试选项构建的库中。
如果副本不相同,则 armlink 会根据输入对象的属性保留每个公共节组的最佳可用变体。Armlink 丢弃其余部分。
如果副本相同,则 armlink 将保留位于的第一个部分组。
您可以使用以下链接器选项来控制此优化:
- 使用 -
-bestdebug选项使用最大的公共数据 (COMDAT) 组(可能提供最佳调试视图)。 -
使用 -
-no_bestdebug选项使用最小的 COMDAT 组(可能提供最小的代码大小)。这是默认设置。如果使用 -
g编译包含 COMDAT 组 A 的所有文件,即使使用 --no_bestdebug,映像也会更改。
消除未使用的部分
消除未使用的部分是链接器对图像大小执行的最重要优化。
未使用部分消除:
- 从最终映像中删除无法访问的代码和数据。
- 在可能导致删除所有部分的情况下被禁止显示。
要控制此优化,请使用 armlink 选项 --remove、--no_remove、--first、--last 和 --keep。
未使用的部分消除需要一个入口点。因此,如果未为映像指定入口点,请使用 armlink 选项 --entry 指定入口点。
使用 armlink 选项 --info unused 指示链接器生成它删除的未使用部分的列表。
注意
armlink报告错误:L6218E:未定义的符号 <symbol>,即使未使用的部分删除已删除此符号的要求。此行为与 GNU 链接器ld不同。
在以下情况下,输入部分将保留在最终图像中:
- 它包含一个入口点或一个外部可访问的符号。例如,Arm®v8-M 安全扩展的安全代码中的输入函数。
- 它是
SHT_INIT_ARRAY、SHT_FINI_ARRAY或SHT_PREINIT_ARRAY部分。 - 它被指定为第一个或最后一个输入部分,由 --
first或--last选项或分散加载等效项指定。 - 它被
--keep选项标记为不可删除。 - 它直接或间接地由图像中保留的输入部分的非弱引用引用。
- 其名称与输入截面符号所引用的名称匹配,并且该符号引用自图像中保留的截面。
注意
编译器通常将函数和数据收集在一起,并为每个类别发出一个部分。链接器只能删除完全未使用的部分。
您可以使用
__attribute__(used))属性标记源代码中的函数或变量。此属性使armclang为每个函数或变量生成符号__tagsym$$used.<num>,其中<num>是用于区分每个符号的计数器。消除未使用的部分不会删除包含__tagsym$$used.<num>的部分。您还可以使用
armclang选项 -ffunction-sections来指示编译器为源文件中的每个函数生成一个 ELF 部分。
使用 RW 数据压缩进行优化
RW 数据区通常包含大量重复值(如零),这使得它们适合压缩。
默认情况下,RW 数据压缩处于启用状态,以最小化 ROM 大小。
链接器压缩数据。然后,在运行时在目标上解压缩此数据。
Arm 库包含一些解压缩算法,链接器选择要添加到映像的最佳算法,以便在执行映像时解压缩数据区域。可以重写链接器选择的算法。
链接器如何选择压缩器
Armlink 在选择最合适的压缩算法以生成最小图像之前收集有关数据部分内容的信息。
如果压缩合适,armlink 只能对图像中的所有可压缩数据部分使用一个数据压缩器。可以在这些部分上尝试不同的压缩算法,以生成最佳的整体大小。如果出现以下情况,将自动应用压缩:
Compressed data size + Size of decompressor < Uncompressed data size
选择压缩器后,armlink 会将解压缩器添加到映像的代码区域。如果最终映像不包含任何压缩数据,则不会添加解压缩程序。
可用于替代链接器使用的压缩算法的选项
链接器具有用于禁用压缩或指定要使用的压缩算法的选项。
可以通过以下任一方式替代链接器使用的压缩算法:
- 使用 -
-datacompressor off选项关闭压缩。 - 指定压缩算法。
若要指定压缩算法,请在链接器命令行上使用所需压缩器的编号,例如:
armlink --datacompressor 2 ...
使用命令行选项 --datacompressor list 获取链接器中可用的压缩算法列表:
armlink --datacompressor list
...
Num Compression algorithm
========================================================
0 Run-length encoding
1 Run-length encoding, with LZ77 on small-repeats
2 Complex LZ77 compression
选择压缩算法时,请注意:
- Compressor 0 在具有大量零字节但非零字节较少的数据上表现良好。
- Compressor 1 在处理非零字节重复的数据时表现良好。
- Compressor 2 在处理包含重复值的数据时表现良好。
链接器首选压缩器 0 或 1,其中数据主要包含零字节 (>75%)。选择 Compressor 2 时,数据包含很少的零字节 (<10%)。如果图像仅由 A32 代码组成,则会自动使用 A32 解压缩器。如果映像包含任何 T32 代码,则使用 T32 解压缩器。如果没有明确的偏好,则对所有压缩机进行测试,以产生最佳的整体尺寸。
使用 RW 数据压缩时的注意事项
使用 RW 数据压缩时需要注意一些注意事项。
使用 RW 数据压缩时:
- 使用链接器选项 -
-map查看对代码中的区域应用压缩的位置。 - 如果存在从压缩区域到使用加载地址的链接器定义符号的引用,则链接器将关闭 RW 压缩。
- 如果您使用的是带有片上缓存的 Arm® 处理器,请在解压缩后启用缓存,以避免出现代码一致性问题。
压缩数据段在运行时自动解压缩,前提是使用 Arm 库中的代码执行__main。此代码必须放置在根区域中。最好在散点文件中使用 InRoot$$Sections 来完成此操作。
如果使用的是散点文件,则可以通过添加 NOCOMPRESS 属性来指定不压缩加载或执行区域。
与链接器内联的函数
链接器内联功能取决于您指定的选项和输入文件的内容。
链接器可以内联小函数来代替该函数的分支指令。要使链接器能够执行此操作,函数(没有返回指令)必须适合分支指令的四个字节。
使用 --inline 和 --no_inline 命令行选项来控制分支内联。但是,--no_inline 仅关闭用户提供的对象的内联。默认情况下,链接器仍内联 Arm 标准库中的函数。
如果启用了分支内联优化,则链接器会扫描映像中的每个函数调用,然后根据需要进行内联。当链接器找到合适的函数进行内联时,它会将函数调用替换为正在调用的函数中的指令。
链接器在消除任何未使用的部分之前应用分支内联优化,以便在不再调用内联部分时也可以将其删除。
注意
- 对于 Arm®v7-A,链接器可以内联两个 16 位编码的 Thumb 指令,以代替 32 位编码的 Thumb®
BL指令。- 对于 Armv8-A 和 Armv8-M,链接器可以内联两个 16 位 T32 指令来代替 32 位 T32
BL指令。
使用 --info=inline 命令行选项列出所有内联函数。
关于优化到 NOP 的分支
尽管链接器可以将分支替换为 NOP,但在某些情况下,您可能希望阻止这种情况发生。
默认情况下,链接器将任何分支替换为重新定位,该重定位将解析为具有 NOP 指令的下一条指令。如果链接器对尾部调用部分重新排序,也可以应用此优化。
但是,在某些情况下,您可能希望禁用该选项,例如,在执行验证或管道刷新时。
要控制此优化,请使用 --branchnop 和 --no_branchnop 命令行选项。
尾部调用部分的链接器重新排序
在某些情况下,您可能希望链接器对尾部调用部分重新排序。
尾部调用部分是在该部分末尾包含分支指令的部分。如果分支指令具有以另一个部分开头的函数为目标的重定位,则链接器可以将尾部调用部分放在被调用部分之前。然后,链接器可以将尾部调用部分末尾的分支指令优化为 NOP 指令。
若要利用此行为,请使用命令行选项 --tailreorder 将尾部调用部分移动到其目标之前。
使用 --info=tailreorder 命令行选项可显示有关链接器执行的任何尾调用优化的信息。
对尾部调用部分重新排序的限制
尾部调用部分的重新排序有一些限制。
链接器:
- 对于每个尾部调用目标,只能移动一个尾部调用部分。如果对单个部分有多个尾部调用,则具有相同部分名称的尾部调用部分将移动到目标之前。如果在具有匹配名称的尾部调用部分中找不到部分名称,则链接器将移动它遇到的第一个部分。
- 无法将尾部调用部分移出其执行区域。
- 在内联贴面之前不移动尾部。
合并相同的常量
链接器可以尝试合并以 AArch32 状态为目标的对象中的相同常量。必须使用 Arm® Compiler for Embedded 6 生成对象。如果使用 armclang -ffunction-sections 选项进行编译,则合并效率更高。此选项是默认选项。
关于此任务
以下过程是显示合并功能的示例。
注意
如果使用散点文件,则任何标有OVERLAY或PROTECTED属性的区域都会影响armlink --merge_litpools选项的行为。
程序
- 创建一个 C 源文件
litpool.c,其中包含以下代码:int f1() {return 0xdeadbeef; } int f2() {return 0xdeadbeef; } - 使用
-S编译源代码以创建汇编文件:armclang -c -S -target arm-arm-none-eabi -mcpu=cortex-m0 -ffunction-sections \litpool.c -o litpool.s注意
-ffunction-sections是默认值。由于
0xdeadbeef是一个难以使用指令创建的常量,因此会创建一个文本池,例如:... f1:.fnstart @ BB#0:ldr r0, __arm_cp.0_0bx lr.p2align 2 @ BB#1: __arm_cp.0_0:.long 3735928559 @ 0xdeadbeef ....fnend....code 16 @ @f2.thumb_func f2:.fnstart @ BB#0:ldr r0, __arm_cp.1_0bx lr.p2align 2 @ BB#1: __arm_cp.1_0:.long 3735928559 @ 0xdeadbeef ....fnend ...注意
每个函数都有一个常量副本,因为armclang不能在两个函数之间共享这些常量。 - 编译源代码以创建对象:
armclang -c -target arm-arm-none-eabi -mcpu=cortex-m0 litpool.c -o litpool.o - 使用
--merge_litpools选项链接目标文件:armlink --cpu=Cortex-M0 --merge_litpools litpool.o -o litpool.axf注意
--merge_litpools是默认值。 - 运行
fromelf查看镜像结构:fromelf -c -d -s -t -v -z litpool.axf以下示例显示了合并的结果:
...f10x00008000: 4801 .H LDR r0,[pc,#4] ; [0x8008] = 0xdeadbeef0x00008002: 4770 pG BX lrf20x00008004: 4800 .H LDR r0,[pc,#0] ; [0x8008] = 0xdeadbeef0x00008006: 4770 pG BX lr$d.4__arm_cp.1_00x00008008: deadbeef .... DCD 3735928559 ...
相关文章:
ARM 链接器优化功能介绍
消除公共部分组 链接器可以检测节组的多个副本,并丢弃其他副本。 Arm Compiler for Embedded 生成用于链接的完整对象。因此: 如果 C 和 C 源代码中存在内联函数,则每个对象都包含该对象所需的内联函数的外联副本。如果在 C 源代码中使用…...
动手学深度学习之卷积神经网络之池化层
池化层 卷积层对位置太敏感了,可能一点点变化就会导致输出的变化,这时候就需要池化层了,池化层的主要作用就是缓解卷积层对位置的敏感性 二维最大池化 这里有一个窗口,来滑动,每次我们将窗口中最大的值给拿出来 还是上…...
HackTheBox - Medium - Linux - Ambassador
Ambassador Ambassador 是一台中等难度的 Linux 机器,用于解决硬编码的明文凭据留在旧版本代码中的问题。首先,“Grafana”CVE (“CVE-2021-43798”) 用于读取目标上的任意文件。在研究了服务的常见配置方式后,将在其…...
嵌入式——循环队列
循环队列 (Circular Queue) 是一种数据结构(或称环形队列、圆形队列)。它类似于普通队列,但是在循环队列中,当队列尾部到达数组的末尾时,它会从数组的开头重新开始。这种数据结构通常用于需要固定大小的队列,例如计算机内存中的缓冲区。循环队列可以通过数组或链表实现,…...
2024.1.7-实战-docker方式给自己网站部署prometheus监控ecs资源使用情况-2024.1.7(测试成功)
实战-docker方式给自己网站部署prometheus监控ecs资源使用情况-2024.1.7(测试成功) 目录 最终效果 原文链接 https://onedayxyy.cn/docs/prometheus-grafana-ecs 参考模板 https://i4t.com/ https://grafana.frps.cn 🔰 额,注意哦: 他这个是通过frp来…...
20240107 SQL基础50题打卡
20240107 SQL基础50题打卡 1978. 上级经理已离职的公司员工 表: Employees ----------------------- | Column Name | Type | ----------------------- | employee_id | int | | name | varchar | | manager_id | int | | salary | int | -…...
阿里云公网带宽出网和入网是什么?上行和下行是什么?
什么是阿里云服务器ECS的入网带宽和出网带宽?以云服务器为中心,流入云服务器占用的带宽是入网带宽,流量从云服务器流出的带宽是出网带宽。阿里云服务器网aliyunfuwuqi.com分享入网带宽和出网带宽说明表: 带宽类别说明入网带宽&am…...
eureka工作原理是什么
EUREKA 是一个基于 RESTful 风格的服务发现系统,它主要用于帮助实现在微服务架构中的服务自动发现与注册。其工作原理主要包括以下几个步骤: 注册中心:EUREKA 中有一个集中的注册中心,所有的服务都将在此注册和发现。注册中心可以…...
Vue中的事件委托(事件代理)使用方法介绍
事件委托(事件代理) 将原本需要绑定在子元素上的事件监听器委托在父元素上,让父元素充当事件监听的职务。 事件委托是一种利用事件冒泡的特性,在父节点上响应事件,而不是在子节点上响应事件的技术。它能够改善性能&a…...
「HDLBits题解」Wire decl
本专栏的目的是分享可以通过HDLBits仿真的Verilog代码 以提供参考 各位可同时参考我的代码和官方题解代码 或许会有所收益 题目链接:Wire decl - HDLBits default_nettype none module top_module(input a,input b,input c,input d,output out,output out_n ); w…...
[MAUI]在.NET MAUI中调用拨号界面
在.NET MAUI中调用拨号界面 前置要求: Visual Studio 2022 安装包“.NET Multi-platform App UI 开发” 参考文档: 电话拨号程序 新建一个MAUI项目 在解决方案资源管理器窗口中找到Platforms/Android/AndroidManifest.xml在AndroidManifest.xml中添加下文中…块如下:<?xml…...
Kali/Debian Linux 安装Docker Engine
0x01 卸载旧版本 在安装Docker Engine之前,需要卸载已经安装的可能有冲突的软件包。一些维护者在他们的仓库提供的Docker包可能是非Docker官方发行版,须先卸载这些软件包,然后才能安装Docker官方正式发行的Docker Engine版本。 要卸载的软件…...
Spring 应用合并之路(二):峰回路转,柳暗花明 | 京东云技术团队
书接上文,前面在 [Spring 应用合并之路(一):摸石头过河]介绍了几种不成功的经验,下面继续折腾… 四、仓库合并,独立容器 在经历了上面的尝试,在同事为啥不搞两个独立的容器提醒下,…...
SQL Error 1366, SQLState HY000
SQL错误 1366 和 SQLState HY000 通常指的是 MySQL 与字符编码或数据截断有关的问题。当尝试将数据插入具有与正在插入的数据不兼容的字符集或排序规则的列时,或者正在插入的数据对于列来说过长时,就会出现此错误。 解决方式: 检查列长度&am…...
Codeforces Round 893 (Div. 2)(VP-7,寒假加训)
VP时间 A. 关键在于按c的按钮 c&1 Alice可以多按一次c按钮 也就是a多一个(a) 之后比较a,b大小即可 !(c&1) Alice Bob操作c按钮次数一样 1.ac B.贪心 一开始会吃饼干 如果有卖饼的就吃 如果隔离一段时间到d没吃就吃(当时…...
MySQL第四战:视图以及常见面试题(上)
目录 目录: 一.视图 1.介绍什么是视图 2.视图的语法 语法讲解 实例操作 二.MySQL面试题 1.SQL脚本 2.面试题实战 三.思维导图 目录: 随着数字化时代的飞速发展,数据库技术,特别是MySQL,已经成为IT领域中不可…...
C语言程序设计——程序流程控制方法(一)
C语言关系运算符 ---等于ab!不等于a!b<、>小于和大于a>b 、a<b<、>小于等于、大于等于a>b 、a<b!非!(0)、!(NULL) 在C99之后,C语言开始支持布尔类型,头文件是stdbool.h。在文中我所演示的所有代码均是C99版。 在C语言上上述关…...
torch.backends.cudnn.benchmark
torch.backends.cudnn.benchmark 的设置对于使用 PyTorch 进行深度学习训练的性能优化至关重要。具体而言,它与 NVIDIA 的 CuDNN(CUDA Deep Neural Network library)库有关,该库是在 GPU 上加速深度神经网络计算的核心组件。 启用…...
SQL Server从0到1——写shell
xp_cmdshell 查看能否使用xpcmd_shell; select count(*) from master.dbo.sysobjects where xtype x and name xp_cmdshell 直接使用xpcmd_shell执行命令: EXEC master.dbo.xp_cmdshell whoami 发现居然无法使用 查看是否存在xp_cmdshell: EXEC…...
计算圆弧的起始角度、终止角度和矩形信息并使用drawArc绘制圆弧
Qt中常用绘制圆弧的库函数: //函数原型 void QPainter::drawArc(const QRectF &rectangle, int startAngle, int spanAngle)Qt规定1约占16个像素,比如一个完整的圆等于360度,对应的像素角度就是 5760度(16 * 360)…...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
