You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARM926EJ-S平台运行时函数.text段内存替换实现方案咨询

ARM9架构下动态函数替换实现方案

前置准备

你需要先在自定义链接脚本中完成两项配置:

  • 保证function_1的.text段长度 ≥ function_3的.text段长度,且两段地址都按4字节对齐(ARM指令集)或2字节对齐(Thumb指令集)
  • 配置函数段所在内存页的属性为可读可写可执行,如果开启了MMU需要修改对应页表项的权限位,关闭MMU可跳过该步骤

直接替换.text段的实现(匹配你原本的方案)

该方案和x86下逻辑基本一致,仅需要额外处理ARM架构专属的缓存、指令对齐问题:

  1. 关闭全局中断,避免拷贝过程中触发中断调用半修改状态的function_1导致跑飞
  2. 执行内存拷贝,把function_3的.text段内容完整复制到function_1的起始地址,拷贝长度按function_3的段长度取值
  3. 刷新指令缓存(I-cache),ARM926EJ-S自带指令缓存,修改内存中的指令后缓存中仍留存旧指令,必须手动无效化对应地址的缓存行,参考实现代码:
void flush_icache(uint32_t start_addr, uint32_t end_addr) {
    uint32_t addr;
    // ARM926EJ-S默认I-cache行大小为32字节,逐行无效化
    for (addr = start_addr; addr < end_addr; addr += 32) {
        asm volatile ("mcr p15, 0, %0, c7, c5, 1" : : "r" (addr));
    }
    // 全量无效化I-cache也可,适合不想计算段长度的场景
    asm volatile ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
    // 加三条空指令做屏障,保证缓存操作完成再执行后续逻辑
    asm volatile ("nop");asm volatile ("nop");asm volatile ("nop");
}
  1. 开中断,后续调用function_1就会执行function_3的逻辑

注意:如果你的函数内部使用了绝对地址寻址,需要编译时加-fPIC参数生成位置无关代码,否则拷贝到新地址后寻址会出错,你当前的打印逻辑用相对寻址即可满足,不需要额外处理。

更优的实现路径(不需要拷贝全量函数代码)

直接替换指令的方式受函数长度、位置无关性限制,更稳定的方案是用跳转桩实现:
你可以将function_1的入口修改为仅4字节的跳转指令,初始跳转到原function_1的实现地址,需要替换时只要修改跳转目标地址即可,参考汇编实现:

.global function_1
function_1:
    ldr pc, [pc, #-4]   @ 直接把下方存储的地址加载到PC寄存器实现跳转
    .word real_func1    @ 初始指向原function_1的实现地址

替换时只要把function_1入口后4字节的地址值修改为function_3的地址,再刷新一次I-cache即可完成替换,不需要处理函数长度对齐、位置无关等问题,稳定性更高,性能损耗可以忽略。

内容的提问来源于stack exchange,提问作者Amr Mahmoud

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 09:24:07