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

arm-none-eabi-gcc下Attribute'Address值与实际地址不符的原因咨询

问题:Cortex-M0/STM32F03环境中Attribute'Address获取的地址与实际运行地址不符

在arm-none-eabi-gcc(针对Cortex-M0/STM32F03)环境中,我发现通过Attribute'Address获取的地址,编译时插入的值与实际运行时的真实地址存在差异。以Hardfault_Handler为例,相关信息如下:

代码示例

procedure Hardfault_Handler is
     SP : Address         := Get_Stack_Pointer; -- 保存进入Handler后的栈指针
     PC                 : Address := Get_Program_Counter; -- 保存当前程序计数器
     PC_Offset          : Storage_Offset  := PC - Hardfault_Handler'Address;
     Num_Of_Pushed_Regs : Natural         := 0;
     SP_Calc            : Integer_Address := To_Integer (SP);
     package Thumb_Ins_Pnt is new System.Address_To_Access_Conversions
       (Push_Instruction);
     use Thumb_Ins_Pnt;
     Temp_Ins : Object_Pointer;
  begin
     -- 遍历HardfaultHandler开头的程序代码
     for I in 0 .. PC_Offset when (I mod 2 = 0) loop
        Temp_Ins := To_Pointer (Hardfault_Handler'Address + I);
        -- 判断是否是Push指令?
        if Temp_Ins.Mask = PUSH_Ins_Mask then
           -- 统计压入栈的寄存器数量
           for Bit of Temp_Ins.Regs when Bit = True loop
              Num_Of_Pushed_Regs := Num_Of_Pushed_Regs + 1;
           end loop;
           -- 调整SP指向Push之前的位置(栈向下增长,所以加偏移)
           SP_Calc := SP_Calc + 4 * Integer_Address (Num_Of_Pushed_Regs);

           declare
              Old_Regs : constant Stacked_Registers with
                Import, Address => To_Address (SP_Calc + Stacked_Reg_Offset);
              Old_PC_Content : constant Thumb_Instruction with
                Import, Address => Old_Regs.PC;
           begin
              if Old_PC_Content = Break_Point_Instruction then
                 -- 无调试器连接时触发Hardfault,直接返回
                 return;
              end if;
           end;
        end if;
     end loop;

     Put_Line ("Hard Fault");
     -- 待实现的错误处理逻辑
  end Hardfault_Handler;

objdump输出

08000754 <m0__startup__hardfault_handler>:
   procedure Hardfault_Handler is
 8000754:       b5f8            push    {r3, r4, r5, r6, r7, lr}

   function Get_Stack_Pointer return Address is
      Result : Address;
   begin
      Asm
 8000756:       46ec            mov     ip, sp
   end Get_Stack_Pointer;

   function Get_Program_Counter return Address is
      Result : Address;
   begin
      Asm
 8000758:       467d            mov     r5, pc
      PC_Offset          : Storage_Offset  := PC - Hardfault_Handler'Address;
 800075a:       4e2a            ldr     r6, [pc, #168]  ; (8000804 <m0__startup__hardfault_handler+0xb0>)
   end "-";

存储的Hardfault_Handler'Address值

8000802:       bdf8            pop     {r3, r4, r5, r6, r7, pc}
 8000804:       08000755        stmdaeq r0, {r0, r2, r4, r6, r8, r9, sl}
 8000808:       08002a88        stmdaeq r0, {r3, r7, r9, fp, sp}
 800080c:       7fffffff        svcvc   0x00ffffff
 8000810:       0000beab        andeq   fp, r0, fp, lsr #29
 8000814:       08002a28        stmdaeq r0, {r3, r5, r9, fp, sp}
 8000818:       08002ad8        stmdaeq r0, {r3, r4, r6, r7, r9, fp, sp}

向量表信息

向量表代码

Vector_Table : constant Address_Array :=
     (Sram_Stack_Start, Reset_Handler'Address, NMI_Handler'Address,
      Hardfault_Handler'Address, MemManage_Handler'Address,
      Bus_Fault_Handler'Address, Usage_Fault_Handler'Address, Reserved,
      Reserved, Reserved, Reserved, SVCall_Handler'Address,
      Debug_Handler'Address, Reserved, PendSV_Handler'Address,    
      Systick_Handler'Address, Default_Handler'Address,
      Default_Handler'Address, Default_Handler'Address,
      Default_Handler'Address, Default_Handler'Address,
      Default_Handler'Address, Default_Handler'Address,
      Default_Handler'Address, Default_Handler'Address,
      Default_Handler'Address, Default_Handler'Address,
      Default_Handler'Address, Default_Handler'Address,
      Default_Handler'Address, Default_Handler'Address,
      Default_Handler'Address, Default_Handler'Address,
      Default_Handler'Address, Default_Handler'Address,
      Default_Handler'Address, Default_Handler'Address,
      Default_Handler'Address, Default_Handler'Address,
      Default_Handler'Address);
   --Default_Handler'Address);
   pragma Linker_Section (Vector_Table, "_vector_table");

objdump中的向量表内容

08000000 <m0__startup__vector_table>:
 8000000:       20001000        andcs   r1, r0, r0
 8000004:       080005b1        stmdaeq r0, {r0, r4, r5, r7, r8, sl}
 8000008:       08000699        stmdaeq r0, {r0, r3, r4, r7, r9, sl}
 800000c:       08000755        stmdaeq r0, {r0, r2, r4, r6, r8, r9, sl}
 8000010:       080006b1        stmdaeq r0, {r0, r4, r5, r7, r9, sl}
 8000014:       080006c9        stmdaeq r0, {r0, r3, r6, r7, r9, sl}
 8000018:       080006e1        stmdaeq r0, {r0, r5, r6, r7, r9, sl}
        ...

080005b0 <Reset_Handler>:

   -------------------
   -- Reset_Handler --
   -------------------

   procedure Reset_Handler is
 80005b0:       b570            push    {r4, r5, r6, lr}
      Data_L : Storage_Element with
        Volatile, Import, External_Name => "__data_size";

      Data_Length : constant Storage_Offset := Addr2SO (Data_L'Address);

      Data_Load_Array : Storage_Array (1 .. Data_Length) with
 80005b2:       4c16            ldr     r4, [pc, #88]   ; (800060c <Reset_Handler+0x5c>)
      Bss_L : Storage_Element with
        Volatile, Import, Convention => Asm, External_Name => "__bss_size";

问题

向量表中的地址同样存在差异,但Reset_Handler能正常调用运行。请问该现象的原因是什么?


原因分析

这是Cortex-M系列处理器的Thumb指令集地址对齐特性导致的:

  1. Thumb指令的最低位标记
    Cortex-M0仅支持Thumb指令集,所有函数的实际执行地址都是偶数地址(Thumb指令长度为2或4字节,必须对齐到2字节边界)。但处理器在跳转/调用时,会把地址的最低位(LSB)作为Thumb状态标记:当LSB为1时,说明目标是Thumb指令,处理器会自动清除该位得到真实执行地址。

  2. Attribute'Address的行为
    在Ada中,Hardfault_Handler'Address返回的是带Thumb标记的地址(即真实执行地址+1)。比如:

  • 实际运行地址是08000754(偶数)
  • Attribute'Address给出的是08000755(最低位为1)
  1. 向量表的兼容性
    向量表中必须存储带LSB=1的标记地址,这样处理器复位/触发中断时,才能正确识别这是Thumb指令入口。所以Reset_Handler'Address虽然看起来是080005b1,但处理器会自动去掉最低位,跳转到真实地址080005b0执行,因此能正常运行。

  2. 代码中的修正方法
    你的代码直接用Hardfault_Handler'Address计算指令偏移、访问指令内存,相当于用了带标记的地址,会指向指令的第二个字节,自然出现错误。解决方法是在使用地址前手动清除最低位:

-- 获取真实执行地址
Real_Handler_Addr : Address := To_Address(To_Integer(Hardfault_Handler'Address) and 16#FFFFFFFE#);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 21:51:48