Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
IAP_在线更新
编译问题
PIC地址无关编译
100
编译与位置无关的目标文件
发布于 2024-05-22 13:49:07 浏览:258
订阅该版
[tocm] ## 前言: 做这个功能的原因是:我们目前升级是boot + 双app, 这两个app交差升级, 这回导致必须编译两个有不同链接地址的bin文件, 而且升级的时候需要根据升级地址选择对应文件, 这增加了一定的复杂程度, 所以想编译出来一个与位置无关的bin文件, 使其能烧录到任意地址都能运行, 只需要boot指定目标地址就行了. ## 问题: 代码中直接通过函数名调用的地方都可以根据PC偏移来找到, 但是对于使用函数指针的地方, 比如在rtthread 中使用 INIT_BOARD_EXPORT(fn) 初始化的地方, 这些函数被统一硬件编址到了目标文件, 不过这个统一在一个地方调用,倒可以在调用前修正一下.但是对于其他用函数指针的来调用的地方就有问题了, 函数地址也被硬编码到了目标文件中, 烧录到不同地址后再引用这个函数就会出错 下面描述一下我目前做的修改点,希望有大佬帮忙看看是否我哪里没有做对才导致了我的上述问题 ## 开发环境是 ENV + GCC + GD32F303 编译选项增加了以下几个 ```python CFLAGS += ' -fPIC' #生成与位置无关代码 CFLAGS += ' -mno-pic-data-is-text-relative' #不让任何变量相对于PC寻址 CFLAGS += ' -mpic-register=r9' #让pic基于R9寄存器偏移 ``` ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240524/8c4f445b51306d3b8f36607d08ed0267.png.webp) ## 链接脚修改 ```c MEMORY { CODE (rx) : ORIGIN = 0x08002000, LENGTH = 122k DATA (rw) : ORIGIN = 0x20000020, LENGTH = 48*1024-0x20 } ``` 其中 0x08000000 - 0x08002000 这部分空间用来存放bootloader代码 0x20000000 - 0x20000020 这部分用来在启动文件中存放一些元数据(flash偏移, 向量表地址, GOT表地址) data段增加GOT表 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240524/43bb0e6a295ac5c3eab049c17115f648.png.webp) 启动文件修改 只修改了 复位处理函数 增加的代码将 flash偏移地址, GOT表地址信息, 向量表地址信息 放到RAM 的起始位置,以及将GOT 表偏移地址放入R9, 然后修正got表以及中断向量表(update_vtor update_got这两个函数在后面) ```c Reset_Handler: /*struct app_metamessage_t */ /*保存flash偏移地址 0x20000000*/ mov r8, PC sub r8, 4 ldr r1, =Reset_Handler sub r8, r1 add r8, #1 ldr r1, =0x20000000 str r8, [r1, #0] /*保存GOT起始地址 0x20000004*/ add r1, #4 ldr r2, =GOT_START str r2, [r1, #0] /*保存GOT结束地址 0x20000008*/ add r1, r1, #4 ldr r2, =GOT_END str r2, [r1, #0] /*保存向量表起始地址 0x2000000c*/ add r1, #4 ldr r2, =VT_START str r2, [r1, #0] /*保存向量表结束地址 0x20000010*/ add r1, #4 ldr r2, =VT_END str r2, [r1, #0] /*保存 GOT PIC 基地址*/ ldr r9, =GOT_START /*将flash 偏移量放到寄存器r8 中*/ ldr r1, =0x20000000 ldr r8, [r1] ldr r1, =_sidata /*修正data 拷贝flash 偏移*/ add r1, r8 /*------------------------*/ ldr r2, =_sdata ldr r3, =_edata subs r3, r2 ble fill_bss_start loop_copy_data: subs r3, #4 ldr r0, [r1,r3] str r0, [r2,r3] bgt loop_copy_data fill_bss_start: ldr r1, =__bss_start ldr r2, =__bss_end movs r0, 0 subs r2, r1 ble startup_enter loop_fill_bss: subs r2, #4 str r0, [r1, r2] bgt loop_fill_bss startup_enter: /*修正以及重定向中断向量表 */ bl update_vtor /*修正got表 */ bl update_got bl SystemInit bl entry /* Exception Handlers */ .weak NMI_Handler .type NMI_Handler, %function ``` ## 注释掉代码里原来重定向中断向量表的地方 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240524/83a90ae137aa55eae65f7f3404201f17.png.webp) ## 修改rtthread 堆栈初始化 因为编译器将R9 寄存器用来固定做GOT 偏移, 但是rtthread堆栈初始化的时候强行给R9 写入了0xdeabeef ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240524/459299004ebccebb7b1ffc10a69517d8.png.webp) ## update_got 以及 update_vtor 函数以及向量表重定义实现 ```c struct app_metamessage_t { uint32_t flash_offset; uint32_t got_start; uint32_t got_end; uint32_t vt_start; uint32_t vt_end; }; static struct app_metamessage_t *app_meta = (struct app_metamessage_t *)0x20000000; static uint32_t vtor_ram[256] __attribute__((aligned(1024))); #define FLASH_ADDR_MAX ((256*1024) + 0x08000000) static void update_offset(uint32_t start, uint32_t end) { for (uint32_t *i = (uint32_t *)start; i < (uint32_t *)end; i++) { if ((*i < FLASH_ADDR_MAX) && (*i != 0)) { *i += app_meta->flash_offset; } } } void update_vtor(void) { uint32_t *vt_start = (uint32_t *)(app_meta->vt_start + app_meta->flash_offset); uint32_t *vt_end = (uint32_t *)(app_meta->vt_end + app_meta->flash_offset); uint32_t *vt_ram_start = vtor_ram; while(vt_start < vt_end) { *vt_ram_start++ = *vt_start++; } update_offset((uint32_t)vtor_ram, ((uint32_t)vtor_ram) + (app_meta->vt_end - app_meta->vt_start)); SCB->VTOR = (uint32_t)vtor_ram; } void update_got(void) { update_offset(app_meta->got_start, app_meta->got_end); } ``` ## INIT_BOARD_EXPORT 等自初始化地方调用修正 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240524/9fdd8b5fe03d8ff34af11948a79f8450.png.webp) ## bootloader跳转修正 我目前的链接脚本指定的flash 地址为 0x08002000, 所以这里的offset 偏移指的是 对0x08002000的偏移, 这里只支持向后偏移 ```c static void iap_go_app(uint32_t addr) { typedef void (*iap_fun)(void); iap_fun jump_app; uint32_t reset_addr; uint32_t offset = (addr - APP_OFFSET_BASE); __disable_irq(); jump_app=(iap_fun)(*(uint32_t *)(addr+4)); __set_MSP(*(uint32_t *)addr); reset_addr = (*(uint32_t *)(addr+4)); reset_addr += offset; jump_app = (iap_fun)reset_addr; jump_app(); } int main(void) { iap_go_app(0x08002000); //链接地址和烧录地址和跳转的地址一样的时候可以正常运行 // iap_go_app(0x08003000); //如果用jflash强行烧录到0x08003000 这个地址的时候 app里面的函数指针就异常了 while(1); } ``` ------------ 目前我就只做到了这一步, 烧录到不同地址bootloader都能正常跳转并运行但是只要代码中一旦遇到 使用到函数指针的地方就会跑飞 比如对gpio的操作 ```c void rt_pin_mode(rt_base_t pin, rt_base_t mode) { RT_ASSERT(_hw_pin.ops != RT_NULL); _hw_pin.ops->pin_mode(&_hw_pin.parent, pin, mode); //这里的地址被硬编码到了固定地址 } ``` ------------ # 希望有大神看到帮忙看看能否解决这个问题
查看更多
1
个回答
默认排序
按发布时间排序
三世执戟
2024-05-24
这家伙很懒,什么也没写!
不如使用CI脚本,每次发布时,自动生成2份不同地址的固件。 升级固件时,把两份固件打包在一起,boot自动根据烧录地址来选择用哪份。 有压缩的话体积应该还能接受,走WIFI,4G,甚至蓝牙都还行。只要不是NB或lora网络。 不然即使这个问题解决了,下个问题不知道在哪里🐷
撰写答案
登录
注册新账号
关注者
0
被浏览
258
关于作者
cwq1142173025
这家伙很懒,什么也没写!
提问
11
回答
10
被采纳
0
关注TA
发私信
相关问题
1
RT-Thread有用到寄存器R9吗?
2
Cortex-M3 动态加载一(地址无关代码实现)
3
分享一篇单片机分散加载机制、地址无关编译的分析文章
4
keil如何创建一个Cortex-M3工程,可以实现与地址无关。
5
RTT-stdio 设置flash地址
6
RT Thread 尝试IAP功能时 分区FLASH无法擦写
7
请问用rtt做bootloader跳转前需要关闭哪些东西?
8
IAP程序下载到80%就下不进去了
9
stm32f103rc IAP通过bootloder写入bin文件跑不起来
10
rtt编写的bootloader可顺利跳转至app但运行异常
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
2
RT-Thread 发布 EtherKit开源以太网硬件!
3
rt-thread使用cherryusb实现虚拟串口
4
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
5
《原子操作:程序世界里的“最小魔法单位”解析》
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
13
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
7
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部