ARM学习(31)编译器对overlay方式的支持

news2024/9/22 15:36:47

ARM学习(31)编译器对overlay方式的支持

1、overlay介绍

overlay:重叠得意思,就是可以重复利用得空间,一般在内存上使用这种空间。比如以Windows操作系统为例,其存储空间(ROM/FLASH)一般相对较大,但是内存相对较少,内存要加载Flash上面得较多数据,就得空间上面重复使用。

比如一个游侠里面油很多动态链接库dll,内存有限,只能加载一部分dll库,当用到一些库时,就会将一些库覆盖掉,然后调用这些库,当然这里有很多替换得算法,比如LRU,least recently used,最近最少使用得会被替换,由于被替换得库不确定,所以加载得地址不确定,这就要求dll可以动态加载,根据加载得地址进行偏移寻址,这就是PIC,位置无关,dll里面得代码均使用相对寻址,所以加载到任何地址均可以使用(理论上)。

嵌入式系统为了运行效率高,往往会在ram上面执行代码(相对Flash),所以ram既要放代码,也要存放数据,相对比较紧张,就会将内存空间重复使用。

嵌入式系统当中往往使用绝对地址寻址,不采用相对地址,笔者这里以不带Linux操作系统得应用场景为例。所以如果需要这种重复利用内存空间,就需要确定一块重复利用得地址,然后加载到这块得代码都需要采用这块得地址来进行编译,即在链接脚本里面指定绝对地址。
在这里插入图片描述
以上图为例,有4个功能代码1-4,都需要运行到动态内存地址,则笔者需要将这4个地址都编译到同一个动态内存的地址,然后需要哪个函数的时候就将哪个函数搬到对应的地址,然后再跳转过去执行。

2、编译器armcc/armclang对overlay的支持

armcc/armclang编译器支持overlay,主要是链接脚本这块的支持,通常情况下,

  • 如果两个.o文件放到同一块地址,
  • 或者两个函数放到同一块地址,都会报错误
    如下:两个overlay区域有重叠,因为链接器的作业就是分配运行地址,当然不能重叠,否则该怎么放置代码和执行code呢?
LR_OVERLAY0 0x30000000  0x1000
{
  ER_OVERLAY0 0x2001E000    0x1000 
  {
    overlay0.o(BANK_SEC, +FIRST)
    overlay0.o(+RO)
    overlay0.o(.text)
  }
}

LR_OVERLAY1 0x30001000  0x1000
{
  ER_OVERLAY1 0x2001E000   0x1000 
  {
    overlay1.o(BANK_SEC, +FIRST)
    overlay1.o(+RO)
    overlay1.o(.text)
  }
}

LR_OVERLAY2 0x30002000  0x1000
{
  ER_OVERLAY2 0x2001E000   0x1000 
  {
    overlay2.o(BANK_SEC, +FIRST)
    overlay2.o(+RO)
    overlay2.o(.text)
  }
}
"AdvanceClock.sct", line 32 (column 17): Warning: L6329W: Pattern overlay0.o(RO) only matches removed unused sections.
"AdvanceClock.sct", line 33 (column 16): Warning: L6314W: No section matches pattern overlay0.o(.text).
"AdvanceClock.sct", line 42 (column 17): Warning: L6329W: Pattern overlay1.o(RO) only matches removed unused sections.
"AdvanceClock.sct", line 43 (column 16): Warning: L6314W: No section matches pattern overlay1.o(.text).
"AdvanceClock.sct", line 52 (column 17): Warning: L6329W: Pattern overlay2.o(RO) only matches removed unused sections.
"AdvanceClock.sct", line 53 (column 16): Warning: L6314W: No section matches pattern overlay2.o(.text).
Error: L6221E: Execution region ER_OVERLAY0 with Execution range [0x2001e000,0x2001e080) overlaps with Execution region ER_OVERLAY1 with Execution range [0x2001e000,0x2001e074).
Error: L6221E: Execution region ER_OVERLAY0 with Execution range [0x2001e000,0x2001e080) overlaps with Execution region ER_OVERLAY2 with Execution range [0x2001e000,0x2001e074).
Error: L6221E: Execution region ER_OVERLAY1 with Execution range [0x2001e000,0x2001e074) overlaps with Execution region ER_OVERLAY2 with Execution range [0x2001e000,0x2001e074).
Finished: 0 information, 6 warning and 3 error messages.
make: *** [out/AdvancedClock.axf] Error 1

为了让链接器识别这种情况,把相同的地址放置多个函数,就必须加一个关键字,笔者找到手册上面的关键字overlay。

如下面例子所述,只要在多个想要执行地址的域空间描述上面加上overlay的关键字,该错误就不会报,
在这里插入图片描述
笔者做了尝试果然是这样,

LR_OVERLAY0 0x30000000  0x1000
{
  ER_OVERLAY0 0x2001E000 OVERLAY   0x1000 
  { 
    overlay0.o(OVERLAY_SEC, +FIRST)
    overlay0.o(+RO)
    overlay0.o(.text)
  }
}

LR_OVERLAY1 0x30001000  0x1000
{
  ER_OVERLAY1 0x2001E000 OVERLAY  0x1000 
  {
    overlay1.o(OVERLAY_SEC, +FIRST)
    overlay1.o(+RO)
    overlay1.o(.text)
  }
}

LR_OVERLAY2 0x30002000  0x1000
{
  ER_OVERLAY2 0x2001E000 OVERLAY  0x1000 
  {
    overlay2.o(OVERLAY_SEC, +FIRST)
    overlay2.o(+RO)
    overlay2.o(.text)
  }
}

在这里插入图片描述
需要注意两点:
1、如果是独立设置加载域,则需要将入口函数声明为root属性,不然跳转的地址异常,可能跑飞等
2、保证函数声明为used,不然链接器会将overlay里面的函数stripped掉(删除掉),因为没有用到。
3、注意声明的OVERLAY 属性要放在执行域 长度属性的前面,不然会报错
4、因为笔者用的cm4架构,跳转的时候需要注意使用奇地址,不然可能会跑飞。

LR_OVERLAY0 0x30000000  0x1000
{
  ER_OVERLAY0 0x2001E000 OVERLAY   0x1000 
  { 
    overlay0.o(+RO)
    overlay0.o(.text)
  }
}

LR_OVERLAY1 0x30001000  0x1000
{
  ER_OVERLAY1 0x2001E000 OVERLAY  0x1000 
  {
    overlay1.o(+RO)
    overlay1.o(.text)
  }
}

LR_OVERLAY2 0x30002000  0x1000
{
  ER_OVERLAY2 0x2001E000 OVERLAY  0x1000 
  {
    overlay2.o(+RO)
    overlay2.o(.text)
  }
}
overlay1函数实例,没有root属性,只有used属性。
__attribute__((used))  static  void overlay_handler(u8 overlay_id, u8 func_id)
{
    switch(func_id)
    {
        case 1:
        {
            rt_kprintf("this is overlay func,overlay id=%d func id=%d\r\n", overlay_id, func_id);
        }break;
        default:
        rt_kprintf("this is overlay func,func id=%d,err\r\n", func_id);
        break;
    }
}

笔者尝试了如果不加root属性,则overlay1和overlay则会入口函数是编译器生成的code,会异常。
在这里插入图片描述
编译器生成的code如下:不是压栈所操作,入口地址变成了2001E00C,所以可能导致跑飞
在这里插入图片描述

正常的code应该如下所示:
在这里插入图片描述

如果不加used以及根区属性,则符号都没有被链接进来,因为overlay的函数本身需要运行态来决定运行哪个函数的,所以静态编译的时候编译器并不知道链接哪个,不过不指定used属性,则就会全部strpped掉。

 static  void overlay_handler(u8 overlay_id, u8 func_id)
{
    switch(func_id)
    {
        case 2:
        {
            rt_kprintf("this is overlay func,overlay id=%d func id=%d\r\n", overlay_id, func_id);
        }break;
        default:
        rt_kprintf("this is overlay func,func id=%d,err\r\n", func_id);
        break;
    }
}

在这里插入图片描述
如果overlay属性位置放错,就会报如下错误。

"AdvanceClock.sct", line 29 (column 36): Error: L6228E: Expected '{', found 'O...'.
"AdvanceClock.sct", line 29 (column 36): Error: L6228E: Expected '}', found 'EOF'.
Not enough information to list the image map.
Finished: 1 information, 0 warning and 2 error messages.
make: *** [out/AdvancedClock.axf] Error 1

关于链接脚本的其他关于overlay的写法如下图所示:

  • region1 不是overlay属性,则region2的地址是region1地址的末地址
  • region1 是overlay属性,且offset是0,则region2和region1的地址一样
  • region1 是overlay属性,且offset不是0,则region2是region1末地址+offset
    在这里插入图片描述
    跳转的时候使用奇地址,不然会报错,因为cm4使用thumb指令,
overlay_handler_fun overlay_handler_func = (overlay_handler_fun)(overlay_EXEC_ADDR+1);

在这里插入图片描述

笔者写了一个参考例子如下:
overlay manager:
set_overlay_id,会请求切换当前的bank,
overlay_process,会处理当前的请求,并执行函数。

#include "main.h"


#define overlay_EXEC_ADDR 0x2001E000


#define overlay0_SAVE_ADDR  0x08020000
#define overlay1_SAVE_ADDR  0x08020400
#define overlay2_SAVE_ADDR  0x08020800
#define overlay_FLASH_BASE  overlay0_SAVE_ADDR


typedef void (*overlay_handler_fun)(u8 overlay_id,u8 func_id);

u8 current_overlay_id_g = 0;
u8 set_overlay_id_g = 0;
void overlay_init()
{
    u32 current_overlay_flash_addr = overlay_FLASH_BASE + current_overlay_id_g*0x400;
    STMFLASH_Read(current_overlay_flash_addr, (u32*)overlay_EXEC_ADDR, 0x400);
    overlay_handler_fun overlay_handler_func = (overlay_handler_fun)(overlay_EXEC_ADDR+1);
    (*overlay_handler_func)(current_overlay_id_g, current_overlay_id_g);
}

void set_overlay_id(u8 req_overlay_id)
{
    set_overlay_id_g = req_overlay_id;
}

void overlay_process()
{
    if(set_overlay_id_g != current_overlay_id_g)
    {
        current_overlay_id_g = set_overlay_id_g;
        u32 current_overlay_flash_addr = overlay_FLASH_BASE + current_overlay_id_g*0x400;
        STMFLASH_Read(current_overlay_flash_addr, (u32*)overlay_EXEC_ADDR, 0x400);
        overlay_handler_fun overlay_handler_func = (overlay_handler_fun)(overlay_EXEC_ADDR+1);
        (*overlay_handler_func)(current_overlay_id_g, current_overlay_id_g);
    }
}
#include "main.h"


overlay0.c
__attribute__((section("overlay_SEC"),used))  static void overlay_handler(u8 overlay_id, u8 func_id)
{
    switch(func_id)
    {
        case 0:
        {
            rt_kprintf("this is overlay func,overlay id=%d func id=%d\r\n", overlay_id, func_id);
        }break;
        default:
         rt_kprintf("this is overlay func,func id=%d,err\r\n", func_id);
        break;
    }
}
overlay1.c
__attribute__((section("overlay_SEC"),used))  static  void overlay_handler(u8 overlay_id, u8 func_id)
{
    switch(func_id)
    {
        case 1:
        {
            rt_kprintf("this is overlay func,overlay id=%d func id=%d\r\n", overlay_id, func_id);
        }break;
        default:
        rt_kprintf("this is overlay func,func id=%d,err\r\n", func_id);
        break;
    }
}
overlay2.c
 __attribute__((section("overlay_SEC"),used)) static  void overlay_handler(u8 overlay_id, u8 func_id)
{
    switch(func_id)
    {
        case 2:
        {
            rt_kprintf("this is overlay func,overlay id=%d func id=%d\r\n", overlay_id, func_id);
        }break;
        default:
        rt_kprintf("this is overlay func,func id=%d,err\r\n", func_id);
        break;
    }
}

实际效果如下:
在这里插入图片描述
在这里插入图片描述
如果有Trace32调试器,可以通过Trace32对overlay的支持来进行调试。
trace32 设置指令:

  1. system.option.ovarlay ON
  2. symbol.overlay.AUTOID 自动识别ID
  3. symbol.overlay.list 查看当前处于哪个overlay
    由下图可以可以看到笔者的overlay 处于overlay1,根据右边的打印,然后trace32调试器也显示的overlay1.
    在这里插入图片描述
    笔者切到overlay2,则对应的调试器显示overlay2。
    在这里插入图片描述

3、参考

armcc官方手册
DUI0472M_armcc_user_guide
DUI0474M_armlink_user_guide

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

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

相关文章

springboot垂钓服务系统-计算机毕业设计源码17434

摘要 本文旨在针对垂钓爱好者的需求,基于微信小程序平台,设计并实现一套垂钓服务系统。首先,通过对用户需求进行调研和分析,确定了系统的基本功能模块,包括垂钓点信息展示、用户预约和支付、钓具租赁信息等。接着&…

WebView加载数据的几种方式

之前客户端加载H5时遇到了一些问题,我为了方便解决问题,所以将对应场景复刻到了Demo中,从之前的网络加载模拟为了本地加载Html的方式,但是没想到无意被一个基础知识点卡了一些时间,翻看往昔笔记发现未曾记录这种基础场…

【MATLAB源码】机器视觉与图像识别技术(7)续---BP神经网络

系列文章目录在最后面,各位同仁感兴趣可以看看! BP神经网络 第一节、BP网络定义第二节、BP网络结构及其特点第三节、信息传播方式 信息的正向传播:实质是计算网络的输出误差的反向传播:实质是学习过程第四节、 BP网络的算法流程…

python:plotly 网页交互式数据可视化工具

pip install plotly plotly-5.22.0-py3-none-any.whl pip install plotly_express 包含:GDP数据、餐厅的订单流水数据、鸢尾花 Iris数据集 等等 pip show plotly Name: plotly Version: 5.22.0 Summary: An open-source, interactive data visualization librar…

每日OJ_牛客HJ60 查找组成一个偶数最接近的两个素数

目录 牛客HJ60 查找组成一个偶数最接近的两个素数 解析代码 牛客HJ60 查找组成一个偶数最接近的两个素数 查找组成一个偶数最接近的两个素数_牛客题霸_牛客网 解析代码 首先需要判断素数,素数表示除过1和本身,不能被其它数整除。通过循环遍历来判断一…

飞致云开源社区月度动态报告(2024年7月)

自2023年6月起,中国领先的开源软件公司FIT2CLOUD飞致云以月度为单位发布《飞致云开源社区月度动态报告》,旨在向广大社区用户同步飞致云旗下系列开源软件的发展情况,以及当月主要的产品新版本发布、社区运营成果等相关信息。 飞致云开源大屏…

pycharm怎么使用Anaconda和配置

打开Anaconda Prompt 要删除 Conda 环境 yolov5sconda,你可以使用以下命令: conda remove --name yolov5sconda --all这个命令会删除名为 yolov5sconda 的整个环境,包括其中安装的所有包和依赖项。请在命令提示符或终端中运行此命令。执行此…

Java线程池的设计与使用

Java线程池的设计与使用 多线程情景引入 情景分析 请求积压的情况 系统资源受限: 当大量用户请求同时到来时,服务器受限于内存、CPU、和网络带宽等资源,导致用户长时间等待。后端处理能力限制: 如频率限制措施(每秒或每几秒的访问限制&…

嵌入式day15

数组指针 能够指向整个数组 一维数组: &a,考察a的数据类型 int(*p)[10]:表示一个指向长度为10的一维整型数组的指针 二维数组: 指向函数的指针 函数的函数名,即为函数的入口地址&#x…

亲测推荐!PixPin便捷高效,让你的截图工作轻松搞定,还在等什么?

前言 如果你经常使用电脑,是不是也经常遇到这样的烦恼:需要频繁地截图、标注、编辑图片,可是手里的截图工具却总是那么不给力?要么功能单一,要么操作复杂,让人头疼不已;今天咱们的小江湖就要给大…

企业邮箱收发垃圾邮件拦截吗?

企业邮箱如何拦截垃圾邮件呢?企业邮箱拦截垃圾邮件是采用用户定制化和多层防御机制,确保信息安全。用户参与改进系统,提供技术支持。本文详细介绍了企业邮箱过滤垃圾邮件的机制以及企业邮箱的注册流程。 一、企业邮箱面临的垃圾邮件挑战 1、…

对 vllm 与 ollama 的一些研究

今天咱们来聊聊 vllm 和 ollama 这两个听起来就挺酷的玩意儿。这俩都是现在 AI 圈子里的大明星,专门用来让那些超大型的 AI 模型跑得更顺溜。 先说说 vllm 吧,这家伙的绝活儿是剪枝。啥叫剪枝呢?想象一下,你有个花园,…

OpenCV学习笔记 比较基于RANSAC、最小二乘算法的拟合

一、RANSAC算法 https://skydance.blog.csdn.net/article/details/134887458https://skydance.blog.csdn.net/article/details/134887458 二、最小二乘算法 https://skydance.blog.csdn.net/article/details/115413982

基于cubeMX的STM32的模拟SPI驱动的OLED显示

1、OLED的型号为7针SPI接口 2、cubeMX的设置 (1)GPIO设置 需要注意的是,OLED的五个引脚是普通的IO口来模拟SPI通信,而不是真的用到了单片机的SPI模块。 (2)时钟设置 最后生成代码。 3、打开工程代码 &a…

如何调节超声驱动的功率和频率

超声波驱动板的功率调节是一个关键的技术操作,它直接影响到超声波设备的运行效果和性能。通过适当的功率调整,可以确保超声波设备在最佳状态下工作,从而提高其效率和应用效果。以下是具体的分析: 理解功率调节基础: 超…

Linux 系统下载 wgent

目录 1. yum 命令 2. 下载 wget 操作系统安装软件的方式有很多种,一般分为: (1)下载安装包自行安装; (2)系统的应用商店内安装; Linux 系统同样支持这两种方式: 另…

ShardingSphere实战(3)- 快速实现分库分表

上篇博客,我们讲了 ShardingSphere实战(2)- 水平分表 ,这篇博客,我们继续实现分库以及解决前面遗留的问题。 一、绑定表 基于上篇博客配置的前提下(上篇博客的最后放上了完整的配置,需要的可以…

PCI-e(篇一):科普——PCI-e到底是什么?PCI-e的前世今生

一、什么是PCIE接口? PCI-e接口的全称是Peripheral Component Interconnect Express,是一种高速串行计算机扩展总线标准。它原来的名字是“3GIO”,是由Intel在2001年提出的,旨在替代旧的PCI,PCI-X和AGP总线标准。 PC…

SpringBoot使用泛型出入参+策略模式+反射+缓存实现统一POST接口入口

简介 某些情况下需要统一入口,如:提供给第三方调用的接口等。减少接口对接时的复杂性。 代码实现 GenericController.java 统一入口,通过bean name进行调用service层invoke方法 import com.fasterxml.jackson.databind.ObjectMapper; imp…

Python爬虫入门(结合网站代码演示)

原理 第一步发送请求 与浏览器请求访问服务器地址一样,python程序向服务器发送访问请求,服务器返回数据。 在python中我们可以使用 第二步解析网页内容 浏览器在接收到服务器返回的数据后,会自行解析内容最后呈现出我们所看到的界面。但是在程…