如何让GNU链接器为ARM Cortex M0+的汇编函数生成远调用存根?
要让链接器为你的汇编实现FPU库自动生成远调用存根,核心是让汇编生成的目标文件具备和C++编译代码一致的ARM-EABI属性,这样链接器会将其视为符合标准调用规范的函数,自动处理跨地址空间的调用。
步骤1:添加正确的EABI属性到汇编文件
在你的.cpu cortex-m0plus和.thumb指令之后,添加以下.eabi_attribute指令,这些属性匹配Cortex-M0+的ARM-EABI过程调用标准(PCS),和C++编译生成的目标文件属性对齐:
.cpu cortex-m0plus .thumb ; 配置ARM-EABI属性,让链接器识别为标准EABI目标 .eabi_attribute 7, 1 ; Tag_ABI_Thumb_ISA_use = 使用Thumb-1指令集(Cortex-M0+仅支持此) .eabi_attribute 18, 0 ; Tag_ABI_PCS_WP_enable = 禁用写保护栈指针 .eabi_attribute 20, 0 ; Tag_ABI_PCS_GOT_use = 不使用GOT表 .eabi_attribute 21, 1 ; Tag_ABI_PCS_RW_data = 读写数据4字节对齐 .eabi_attribute 23, 3 ; Tag_ABI_PCS_RO_data = 只读数据4字节对齐 .eabi_attribute 24, 1 ; Tag_ABI_PCS_stack_alignment = 栈8字节对齐 .eabi_attribute 25, 1 ; Tag_ABI_PCS_LR_size = LR寄存器为4字节
如果不确定具体属性,可以用objdump -x your_cpp_object.o查看C++编译生成的目标文件的EABI属性,直接复制对应的指令到汇编文件中,确保完全一致。
步骤2:将汇编函数分配到RAM段
在汇编函数定义前,指定其所在的RAM段(比如.ramfunc,和C++代码中__attribute__((section(".ramfunc")))对应),并正确声明全局函数:
; 指定函数存放到.ramfunc段,该段会被链接器分配到RAM .section .ramfunc,"ax",%progbits .global fpu_mul_func ; 声明为全局函数,供外部调用 .type fpu_mul_func, %function ; 标记为函数类型 fpu_mul_func: ; 你的FPU汇编实现代码 bx lr
步骤3:配置链接脚本确保RAM段正确映射
修改链接脚本,将.ramfunc段分配到RAM地址空间,同时设置Flash作为加载地址(这样函数代码会先存储在Flash,启动时被复制到RAM):
MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K ; 根据你的MCU调整 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K ; 根据你的MCU调整 } SECTIONS { .text : { *(.text*) } > FLASH ; 代码段存Flash .ramfunc : { __RAM_FUNC_START = .; *(.ramfunc*) __RAM_FUNC_END = .; } > RAM AT > FLASH ; RAM函数段加载在Flash,运行在RAM ; 其他段(.data、.bss等)配置... }
如果你的启动代码没有自动复制RAM函数,需要手动添加复制逻辑:从LOADADDR(.ramfunc)复制到__RAM_FUNC_START,直到__RAM_FUNC_END。
步骤4:确保使用ARM-EABI工具链编译
编译时必须使用ARM-EABI工具链(比如arm-none-eabi-as汇编,arm-none-eabi-gcc链接),非EABI工具链不支持远调用存根的自动生成。
完成以上配置后,链接器就会像处理C++的RAM函数一样,为你的汇编FPU函数自动生成远调用存根,解决Flash到RAM调用的地址范围问题。
内容的提问来源于stack exchange,提问作者David Crocker

