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_ARRAYSHT_FINI_ARRAYSHT_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 选项的行为。

程序

  1. 创建一个 C 源文件 litpool.c,其中包含以下代码:
    int f1() {return 0xdeadbeef;
    }
    int f2() {return 0xdeadbeef;
    }
  2. 使用 -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 不能在两个函数之间共享这些常量。
  3. 编译源代码以创建对象:
    armclang -c -target arm-arm-none-eabi -mcpu=cortex-m0 litpool.c -o litpool.o
  4. 使用 --merge_litpools 选项链接目标文件:
    armlink --cpu=Cortex-M0 --merge_litpools litpool.o -o litpool.axf

    注意

    --merge_litpools 是默认值。
  5. 运行 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
    ...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/604115.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

idea 热更新 JRebel 插件激活使用

下载 在 jetbrains 插件网站点击 show more 加载更多版本找到 2022.4.1 版本https://plugins.jetbrains.com/plugin/4441-jrebel-and-xrebel/versions (opens new window) 安装 请勿直接在idea 中搜索安装, 使用从本地安装, 选择刚刚下载的插件, 激活 在设置中找到 JRebel…

Python count()方法:统计字符串出现的次数与字符串拼接(包含字符串拼接数字)

Python count()方法&#xff1a;统计字符串出现的次数 count 方法用于检索指定字符串在另一字符串中出现的次数&#xff0c;如果检索的字符串不存在&#xff0c;则返回 0&#xff0c;否则返回出现的次数。 count 方法的语法格式如下&#xff1a; str.count(sub[,start[,end]]…

macOS通过外置驱动器备份数据

通过外置驱动器备份数据&#xff08;谨慎操作&#xff09; 1.将外置驱动器连接到您的 Mac。驱动器容量应等于或大于您当前的启动磁盘。驱动器还应该是您可以抹掉的。 2.使用 macOS 恢复功能 抹掉外置驱动器&#xff0c;然后将 macOS 安装 到外置驱动器上。确保您选择的外置驱动…

【无线通信专题】NFC通信模式及可能的应用方式

在文章【无线通信专题】NFC基本原理中我们讲到了NFC工作模式。其中NFC工作模式主要有三种,读写模式、卡模拟模式、点对点模式。 NFC通信模式丰富,NFC Forum定义了三种NFC设备:通用NFCForum设备、读写器设备和标签设备。这些NFC设备可以在三种通信模式下运行,并对应用案例进…

如何使用Plex在Windows系统搭建个人媒体站点公网可访问

文章目录 1.前言2. Plex网站搭建2.1 Plex下载和安装2.2 Plex网页测试2.3 cpolar的安装和注册 3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1.前言 用手机或者平板电脑看视频&#xff0c;已经算是生活中稀松平常的场景了&#xff0c;特别是各…

定量评估batch correction质量的方法:混合分数

[41] Bttner, M. et al. A test metric for assessing single-cell RNA-seq batch correction. Nat. Methods 16, 43–49 (2019). 被引次数&#xff1a;297 方法介绍与应用来自论文&#xff1a;Matthew Amodio, David Van Dijk, Krishnan Srinivasan, William S Chen, Hussei…

UE4.27.2 网页串流

1、和Unity串流一样安装Node.js 下载地址https://nodejs.org/ 2、下载安装Epic Games启动程序https://www.unrealengine.com/zh-CN/download 3、安装UE4.7.2 4、这里就不安装像素流送演示&#xff0c;选个别的然后创建工程 5、启用PixelStreaming插件 6、设置额外启动参数&am…

【前端规范】

1 前言 HTML 作为描述网页结构的超文本标记语言&#xff0c;一直有着广泛的应用。本文档的目标是使 HTML 代码风格保持一致&#xff0c;容易被理解和被维护。 2 代码风格 2.1 缩进与换行 [强制] 使用 4 个空格做为一个缩进层级&#xff0c;不允许使用 2 个空格 或 tab 字符…

【ZooKeeper高手实战】ZAB协议:ZooKeeper分布式一致性的基石

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术 的推送 发送 资料 可领取 深入理…

MediaPipeUnityPlugin(最新版)摇摆拳人脸识别

1、从https://github.com/homuler/MediaPipeUnityPlugin 下载Release Package 目前是MediaPipeUnity.0.12.0.unitypackage 2、导入Unity工程 3、打开Face Detection场景&#xff0c;做一些设置修改 1、打开Bootstrap&#xff0c;图像源改成Video&#xff0c;把Solution拖拽到…

day10 用栈实现队列 用队列实现栈

题目1&#xff1a;232 用栈实现队列 题目链接&#xff1a;232 用栈实现队列 题意 用两个栈实现先入先出队列&#xff08;一个入栈&#xff0c;一个出栈&#xff09;&#xff0c;实现如下功能&#xff1a; 1&#xff09;push&#xff1a;将元素x推到队列末尾 2&#xff09;…

基于SpringBoot的医院挂号就诊系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的医院挂号就诊系统,java…

1.7 day5 IO进程线程

互斥锁 #include <myhead.h> char buf[128];//创建临界资源 pthread_mutex_t mutex;//创建锁 void *task(void *arg)//分支线程 {while(1){pthread_mutex_lock(&mutex);//上锁printf("分支线程:buf%s\n",buf);strcpy(buf,"I Love China");pthre…

OpenMMlab导出PointPillars模型并用onnxruntime推理

导出onnx文件 通过mmdeploy的tool/deploy.py脚本容易转换得到PointPillars的end2end.onnx模型。 根据https://github.com/open-mmlab/mmdeploy/blob/main/docs/zh_cn/04-supported-codebases/mmdet3d.md显示&#xff0c;截止目前 mmdet3d 的 voxelize 预处理和后处理未转成 o…

WorkPlus完备的企业级功能堆栈,打造高效的企业移动平台

在如今的数字化时代&#xff0c;企业需要一个完备的功能堆栈来满足复杂的业务需求。WorkPlus作为一个完整的企业级移动平台&#xff0c;拥有完备的企业级功能&#xff0c;如IM、通讯录、内部群、模板群、工作台、权限管控、应用中心、日程管理、邮箱、同事圈、服务号、智能表单…

ROS学习笔记(9)进一步深入了解ROS第三步

0.前提 1. (C)Why did you include the header file of the message file instead of the message file itself?&#xff08;为包含消息的头文件而不是消息本身&#xff1f;&#xff09; 回答&#xff1a;msg文件是描述ROS消息字段的文本文件&#xff0c;用于生成不同语言消息…

银行十大主题域

当事人、产品、协议、事件、资产、财务、机构、地域、营销、渠道 便于记忆&#xff1a; 银行是一个企业&#xff0c;同时也是一个机构&#xff0c;涉及企业机构就会有资产&#xff0c;财务的存在&#xff0c;银行有自己的产品&#xff08;信用卡&#xff0c;黄金&#xff0c;期…

SpringCloud中网关拿到的路径(使用nacos做配置中心)

配置中心 - id: systemuri: lb://systempredicates:- Path=/system/**filters: - StripPrefix=1这里会消去system这一层的请求 网关代码 import org.springframework.cloud.gateway.filter.GatewayFilterChain; import

《微信小程序开发从入门到实战》学习七十四

6.8 文件API 使用文件API可以对用户手机设备中的文件进行一些操作。 为安全考虑&#xff0c;不同小程序间保存的文件是互相隔离的&#xff0c; 小程序外部获取的文件&#xff08;如从手机中选择的文件&#xff09;在小程序中也都是以临时文件存在的。 6.8.1 选择文件API 使…

2024.1.7 Spark SQL , DataFrame

目录 一 . SparkSQL简介 二 . Spark SQL与HIVE的异同 三 . DataFrame 1. 创建 DataFrame 2. RDD转换DataFrame 四 . 操作DataFrame SQL方式: DSL方式: 一 . SparkSQL简介 Spark SQL只能处理结构化数据 ,属于Spark框架一个部分 Schema:元数据信息 特点: 融合性 ,统一数…