使用GCC Arm工具链开发的项目, 在升级到 arm-gnu-toolchain-12.2 之后, 编译出现警告

arm-gnu-toolchain-12.2.mpacbti-bet1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: warning: Build/app.elf has a LOAD segment with RWX permissions

关于 LOAD segment with RWX permissions 警告

这是 Binutils 2.39 引入的一个新的安全类型的警告, GCC在升级版本时会带着新版本的 Binutils 一起发布. 如果要消除这个警告, 要么修改ld文件, 要么屏蔽掉它.

说明

这篇文章里有比较详细的说明
https://www.redhat.com/en/blog/linkers-warnings-about-executable-stacks-and-segments

The executable segment warnings

当程序载入内存时会分段载入, 一些属于可执行的代码,一些属于数据, 可读或者可读可写, 可能还有一些用于其它特殊用途. 每一段内存都会区分可读、可写和可执行这三个属性, 如果一个内存段同时具有这三种属性, 则存在受到攻击的可能性, 因此在这种情况下链接器将产生以下警告

warning: <file> has a LOAD segment with RWX permissions

这个警告表示elf文件中存在一个或多个存在安全问题的段, 可以通过运行readelf程序进行查看

readelf -lW <file>

注意: 在readelf的输出中, 段的可执行标志被标记为E而不是X, 三个属性的标识为RWE而不是RWX. 警告出现的常见原因是使用自定义连接脚本进行链接, 该脚本未将代码和数据分成不同的段, 所以最好的解决办法是更新连接脚本. readelf命令将显示每个段包含哪些部分, 可以通过这些信息计算出连接器映射需要如何更新, 才能将代码部分和可写的数据部分分开.

消除 LOAD segment with RWX permissions 警告

选项一: 使用 --no-warn-rwx-segments 屏蔽

  • 如果连接使用的是ld, 可以用--no-warn-rwx-segments选项
  • 如果连接使用的是gcc, 直接用会提示无法识别的选项, 需要用-Wl,--no-warn-rwx-segments这样的方式

选项二: 修改连接描述

对于存在问题的elf, 可以通过这个命令查看文件结构, 注意后面的Flg部分, RWE分别表示Read,Write,Execute.

$ readelf -lW app.elf Elf file type is EXEC (Executable file)
Entry point 0x15e1
There are 3 program headers, starting at offset 52Program Headers:Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg AlignLOAD           0x010000 0x00000000 0x00000000 0x026f4 0x026f4 RWE 0x10000LOAD           0x020000 0x20000000 0x000026f4 0x00088 0x00334 RW  0x10000LOAD           0x000334 0x20000334 0x0000277c 0x00000 0x00004 RW  0x10000Section to Segment mapping:Segment Sections...00     .isr_vector .text .rodata .init_array .fini_array 01     .data .bss 02     ._user_heap_stack

其中LOAD 0x010000 0x08000000 0x08000000 0x03ffc 0x03ffc RWE 0x10000就是存在问题的segment, 如果要消除这个警告, 可以将ld文件中的 .init_array 和 .fini_array 这部分注释掉, 代码如下. 这部分是 startup 文件中 __libc_init_array使用的, 如果不需要可以直接删除, 对应的编译参数也可以加上-nostartfiles.

  .preinit_array     :{PROVIDE_HIDDEN (__preinit_array_start = .);KEEP (*(.preinit_array*))PROVIDE_HIDDEN (__preinit_array_end = .);} >FLASH.init_array :{PROVIDE_HIDDEN (__init_array_start = .);KEEP (*(SORT(.init_array.*)))KEEP (*(.init_array*))PROVIDE_HIDDEN (__init_array_end = .);} >FLASH.fini_array :{PROVIDE_HIDDEN (__fini_array_start = .);KEEP (*(SORT(.fini_array.*)))KEEP (*(.fini_array*))PROVIDE_HIDDEN (__fini_array_end = .);} >FLASH

这样编译完之后的结果如下, 第一个segment中, Flg变成了R E就没问题了.

$ readelf -lW app.elf Elf file type is EXEC (Executable file)
Entry point 0x1549
There are 3 program headers, starting at offset 52Program Headers:Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg AlignLOAD           0x010000 0x00000000 0x00000000 0x02654 0x02654 R E 0x10000LOAD           0x020000 0x20000000 0x00002654 0x00088 0x00318 RW  0x10000LOAD           0x000318 0x20000318 0x000026dc 0x00000 0x00300 RW  0x10000Section to Segment mapping:Segment Sections...00     .isr_vector .text .rodata 01     .data .bss 02     ._user_heap_stack

上面这种修改并不是通用的, 对于需要使用libc的应用而言并不可行.

实际上, 对于Cortex M系列的MCU而言, elf中第一个segment对应的实际上是烧录到flash中的部分(可执行), 第二个segment对应的才是运行时可读写的内存部分(数据), 第一个segment在通过flash启动正常运行时并不存在修改的可能性.

因此结论是可以通过选项一, 简单地将警告屏蔽掉

参考

  • https://github.com/raspberrypi/pico-sdk/issues/1029
  • https://stackoverflow.com/questions/73429929/gnu-linker-elf-has-a-load-segment-with-rwx-permissions-embedded-arm-project
  • https://github.com/OP-TEE/optee_os/issues/5471

GCC Arm 12.2编译提示 LOAD segment with RWX permissions 警告相关推荐

  1. GCC Arm 11.3rel1, 12.2编译提示 _close is not implemented and will always fail

    使用GCC Arm工具链开发的项目, 在11.2下编译正常, 但是升级到 arm-gnu-toolchain-11.3.rel1 以及 arm-gnu-toolchain-12.2 之后, 编译出现警 ...

  2. arm linux gcc 4.6.3,编译gcc-4.6.3

    编译gcc-4.6.3 准备 下载GCC 源码包 : gcc-4.6.3.tar.bz2 下载GCC 依赖包: gmp-5.0.4.tar.bz2, mpfr-3.1.0.tar.bz2 ,mpc-0 ...

  3. gcc/g++等编译器 编译原理: 预处理,编译,汇编,链接各步骤详解

    例子:由多个源文件组成的C程序,经过编辑.预处理.编译.链接等阶段才能生成最终的可执行程序.此过程中,在__c__阶段可以发现被调用的函数未定义. A. 编辑和预处理 B. 预处理 C. 编译 D. ...

  4. OpenCV4.0.1/4.0.0/3.4.2 + Contrib + Qt5.9 + CMake3.12.1编译及踩坑笔记、Qt5+OpenCV配置、代码验证、效果图、福利彩蛋

    Table of Contents 前言 Windows 10, OpenCV4.0.1, Qt5.9.3, CMake3.12.1, MinGW5.3.0 Windows 10, OpenCV4.0 ...

  5. Xamarin.Android编译提示找不到mscorlib.dll.so文件

    Xamarin.Android编译提示找不到mscorlib.dll.so文件 错误信息:AOT module 'mscorlib.dll.so' not found: Cannot load lib ...

  6. 【嵌入式开发】gcc 学习笔记(一) - 编译C程序 及 编译过程

    一. C程序编译过程 编译过程简介 : C语言的源文件 编译成 可执行文件需要四个步骤, 预处理 (Preprocessing) 扩展宏, 编译 (compilation) 得到汇编语言, 汇编 (a ...

  7. VScode使用记录二:Windows 7下安装GCC、使用VSCode编译代码

    目录 一.概述 二.安装 2.1 GCC编译器 2.2 安装VSCode 2.3 安装插件 三.编译文件 3.1 编译单个文件 3.2 编译多个文件 四.调试程序 一.概述 平时都是在keil下工作, ...

  8. 【Linux-GNU编译器套件(gcc/g++/gfortran)离线编译安装】

    文章目录 Linux-centos7.9系统GNU编译器套件(gcc/g++/gfortran)离线编译安装 一.★GNU编译器套件定义 二.★GNU-GCC编译环境说明 三.★GNU-GCC编译安装 ...

  9. 嵌入式:ARM常用开发编译软件介绍

    文章目录 编译器介绍 1.ADS1.2 2.ARM RealView Developer Suite (RVDS) 3.IAR EWARM 4.KEIL ARM-MDKARM 5.WIN ARM-GC ...

最新文章

  1. 积累这么多年的面试题与经验分享,免费下载
  2. java web 使用https_如何在Web应用程序中实现HTTPS登录页面?
  3. python和sqlserver_利用python实现mysql数据库向sqlserver的同步
  4. 【线段树】Frog Traveler(CF751D)
  5. python中setup什么意思_一个关于python3中setup.py小概念
  6. linux用户与组权限管理
  7. [原创] Wireshark工具培训
  8. 《Kotlin 程序设计》第十一章 Kotlin实现DSL
  9. MATLAB实现一个简单的车牌识别小程序
  10. android导入excel文件格式,android 把数据导入到excel文件中的三种方法
  11. MFC控件与变量的关联和值传递的方法
  12. 河南巴旦木生态农业:巴旦木与杏仁有哪些不同,如何分辨巴旦木仁与杏仁?
  13. python可嵌入和可执行版本_Python可嵌入zip
  14. python海龟画笔速度_【判断题】Python海龟绘图中,设置画笔绘制速度的函数是speed()。...
  15. 这些AI开源项目可以让你创作出卢浮宫级别的艺术品!
  16. android平台下OpenGL ES 3.0给图片添加黑白滤镜
  17. Nowcoder. 链表的回文结构
  18. 如何打造一款直播App(方法流程)
  19. 上海科技领军企业CIMC中集飞瞳集装箱人工智能AI走向成熟,先进产品领跑全球集装箱AI航运港口人工智能应用,上海人工智能企业公司
  20. 逆向工具/反编译工具 集合

热门文章

  1. 婚前买房,婚后加名,离婚时如何分割
  2. 阿里巴巴鹰眼系统了解
  3. 2021苹果春季发表会懒人包:AirTags、iMac、iPad Pro、Apple TV 4K
  4. 如何选择高防服务器。
  5. CycleGAN和Conditional GAN(cGAN)
  6. PostgreSQL批量生成测试数据
  7. 3.开发java的三个步骤
  8. Ping丢包故障处理流程
  9. 最小二乘法(LS算法):实际为L2范数的一个具体应用(计算残差平方和)
  10. 典型的交响乐乐队包括哪些乐器