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

STM32F103裸机汇编中.thumb_func未生效的问题及正确实现方法

STM32F103裸机汇编向量表地址规范问题

问题描述

我尝试用裸机汇编与链接脚本为STM32F103开发小型应用,已编写linker.ld、blink.s及Makefile。生成的blink-asm.bin中,向量表内复位异常处理程序地址为0x08000130,但ARM Cortex-M架构要求该地址需置位最低位(即0x08000131),否则加载到MCU会触发硬 fault。虽然在链接脚本中写LONG(reset_exception_handler + 1)可临时解决,但我预期.thumb_func指令能自动修正reset_exception_handler符号地址。请问编写链接脚本与汇编文件以生成正确地址的规范做法是什么?

现有代码

linker.ld

MEMORY {
    FLASH : ORIGIN = 0x08000000, LENGTH = 64K
    SRAM : ORIGIN = 0x20000000, LENGTH = 20K
}

sp_initial_value = ORIGIN(SRAM) + LENGTH(SRAM);
vector_table_size = 0x130;

SECTIONS {
    vector_table ORIGIN(FLASH) : {
        LONG(sp_initial_value);
        LONG(reset_exception_handler);
    } > FLASH

    .text ADDR(vector_table) + vector_table_size :
    {
    } > FLASH
}
.cpu cortex-m3
.syntax unified
.thumb

.text

.global reset_exception_handler
.thumb_func
.type reset_exception_handler, %function
reset_exception_handler:

add r0, 1
b reset_exception_handler

Makefile

blink-asm.bin: blink-asm.elf
    arm-none-eabi-objcopy -O binary blink-asm.elf blink-asm.bin

flash: blink-asm.bin
    st-flash write blink-asm.bin 0x08000000

blink-asm.elf: blink.o
    arm-none-eabi-ld -T linker.ld -o blink-asm.elf blink.o

blink.o: blink.s
    arm-none-eabi-as -o blink.o blink.s

clean:
    rm -f blink.o blink-asm.elf blink-asm.bin
hexdump -C blink-asm.bin 
00000000  00 50 00 20 30 01 00 08  00 00 00 00 00 00 00 00  |.P. 0...........|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000130  00 f1 01 00 ff f7 fc bf                           |........|

规范解决方案

先明确.thumb_func的实际作用

.thumb_func仅告诉汇编器:后续的标签是Thumb模式函数,汇编器会生成Thumb指令集的代码,并在符号属性中标记其为Thumb函数,但符号本身的数值仍是函数在内存中的实际起始地址(偶数)。链接器不会自动为向量表中的地址添加最低位的模式标记位,因为向量表条目需要的是「内存地址 + 模式标识位」,而非单纯的函数符号地址。

方案1:汇编中定义向量表(推荐)

将向量表定义在汇编文件中,利用汇编器对Thumb函数符号的处理能力,自动为向量表条目添加最低位的1。这种方式更直观,也避免链接脚本中的手动地址计算。

修改后的blink.s:

.cpu cortex-m3
.syntax unified
.thumb

/* 定义向量表段,"a"表示可分配 */
.section .vector_table, "a"
.global __vector_table
__vector_table:
    .word   _estack                  /* 初始栈指针 */
    .word   reset_exception_handler  /* 汇编器自动为Thumb函数地址加1 */
    /* 可继续添加其他异常向量(如NMI、硬fault等) */

/* 定义栈顶地址,等价于原链接脚本中的sp_initial_value */
.global _estack
_estack = 0x20005000  /* 0x20000000 + 20K SRAM */

.text
.global reset_exception_handler
.thumb_func
.type reset_exception_handler, %function
reset_exception_handler:
    add r0, #1
    b reset_exception_handler

简化后的linker.ld:

MEMORY {
    FLASH : ORIGIN = 0x08000000, LENGTH = 64K
    SRAM : ORIGIN = 0x20000000, LENGTH = 20K
}

SECTIONS {
    /* 向量表放在FLASH起始地址 */
    .vector_table ORIGIN(FLASH) : {
        __vector_table = .;
        *(.vector_table)  /* 包含汇编中定义的向量表段 */
    } > FLASH

    /* 代码段紧跟向量表 */
    .text : {
        *(.text)
    } > FLASH
}

方案2:链接脚本中显式处理地址

如果坚持在链接脚本中定义向量表,可直接对函数地址进行位或1操作(因为Thumb函数地址都是偶数,位或1不会改变实际内存地址,仅设置模式位):

修改linker.ld中的向量表部分:

vector_table ORIGIN(FLASH) : {
    LONG(sp_initial_value);
    LONG(reset_exception_handler | 1);  /* 显式设置最低位 */
} > FLASH

这种方式简单直接,且Cortex-M系列仅支持Thumb模式,无需担心兼容性问题。

验证效果

修改后重新编译,查看blink-asm.bin的前8字节,复位向量地址会变为0x08000xxx1(最低位为1),加载到STM32F103后即可正常运行,不会触发硬 fault。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 15:07:38