为什么这个函数确实以 1 的偏移量指向自身?

Mt_*_*266 3 c gcc arm stm32 ld

我正在尝试使用 C 为 Nucleo-64 Stm32F401re 板编写裸机闪烁程序。但是,在开始调试错误时(它还没有闪烁),我发现了一个奇怪的地址,我没有找到任何解释。这是反汇编相关部分的输出:

    blink.elf:     file format elf32-littlearm


Disassembly of section .text:

08000000 <isr_vector_table>:
 8000000:       20018000        andcs   r8, r1, r0
 8000004:       08000009        stmdaeq r0, {r0, r3}

08000008 <Reset_Handler>:
 8000008:       b480            push    {r7}
 800000a:       af00            add     r7, sp, #0
 800000c:       bf00            nop
 800000e:       46bd            mov     sp, r7
 8000010:       bc80            pop     {r7}
 8000012:       4770            bx      lr

Disassembly of section .ARM.attributes:

00000000 <.ARM.attributes>:
   0:   00002d41        andeq   r2, r0, r1, asr #26
   4:   61656100        cmnvs   r5, r0, lsl #2
   8:   01006962        tsteq   r0, r2, ror #18
   c:   00000023        andeq   r0, r0, r3, lsr #32
  10:   2d453705        stclcs  7, cr3, [r5, #-20]      ; 0xffffffec
  14:   0d06004d        stceq   0, cr0, [r6, #-308]     ; 0xfffffecc
  18:   02094d07        andeq   r4, r9, #448    ; 0x1c0
  1c:   01140412        tsteq   r4, r2, lsl r4
  20:   03170115        tsteq   r7, #1073741829 ; 0x40000005
  24:   01190118        tsteq   r9, r8, lsl r1
  28:   061e011a                        ; <UNDEFINED> instruction: 0x061e011a
  2c:   Address 0x0000002c is out of bounds.
Run Code Online (Sandbox Code Playgroud)

Reset_Handler 函数本身在正确的地址上,但是通过在代码中使用它的名称作为指针,它进一步指向一个地址!下面是对应的代码:

extern int _stack_top; // bigger Memory Adress
    
    void Reset_Handler (void);

    __attribute__((section(".isr_vector"))) int* isr_vector_table[] = {

        (int*)&_stack_top,
        (int*)Reset_Handler
    };

    void Reset_Handler (void) {
        
    } 
Run Code Online (Sandbox Code Playgroud)

我使用的链接器脚本与大多数教程中使用的基本相同。

OUTPUT_ARCH(arm)
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
ENTRY(Reset_Handler)

MEMORY
{
    FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
    SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 96K
}

    _stack_top = ORIGIN(SRAM)+LENGTH(SRAM);

SECTIONS
{

    
    
    
    


    .text : 
    {
        . = ALIGN(4);   
        *(.isr_vector)
        *(.text*)
        *(.glue_7)
        *(.glue_7t)
        *(.eh_frame)
        KEEP(*(.init))
        KEEP(*(.fini))
        . = ALIGN(4);
        _etext = .;
    } > FLASH

    .rodata :
    {
        . = ALIGN(4);   
        *(.rodata*)
        . = ALIGN(4);
    } > FLASH

    .ARM.extab :
        {
            *(.ARM.extab* .gnu.linkonce.armextab.*)
    } >FLASH

    .ARM :
     {
            __exidx_start = .;
            *(.ARM.exidx*)
            __exidx_end = .;
     } >FLASH



    .preinit_array :
    {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
    } >FLASH

    .init_array :
    {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
    } >FLASH

    .fini_array :
    {   
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(.fini_array*))
    KEEP (*(SORT(.fini_array.*)))
    PROVIDE_HIDDEN (__fini_array_end = .);
    } >FLASH



    . = ALIGN(4);
    _sidata = LOADADDR(.data);

    .data :
    {
        . = ALIGN(4);
        _sdata = .;
        *(.data*)
        . = ALIGN(4);
        _edata = .;
    } > SRAM AT > FLASH

    .bss :
    {
        . = ALIGN(4);
        _sbss = .;
        __bss_start__ = _sbss;
        *(.bss*)
        *(COMMON)
        . = ALIGN(4);
        _ebss = .;
        __bss_end__ = _ebss;
    } > SRAM

    /DISCARD/ :
    {
         libc.a ( * )
         libm.a ( * )
         libgcc.a ( * )
     }

     .ARM.attributes 0 : { *(.ARM.attributes) }
        
    
    
}
Run Code Online (Sandbox Code Playgroud)

那么为什么存储在 isr_vector_table 中的地址是 08000009 而不是 08000008?到目前为止,我可以将其更改为正确值的唯一方法是通过对该值进行硬编码或为 Reset_Handler 定义一个额外的部分,以便我可以将该地址用作另一个外部值,例如 _stack_top。

这是我用于编译的命令,因为我不知道它们是否需要找到答案:

cd C:/bare_metal
arm-none-eabi-gcc.exe -g main.c -o blink.elf -Wall -T STM32F4.ld -mcpu=cortex-m4 -mthumb --specs=nosys.specs -nostdlib -O0
arm-none-eabi-objdump.exe -D blink.elf
Run Code Online (Sandbox Code Playgroud)

Tag*_*gli 6

来自STM32F4的编程手册PM0214:

向量表
向量表包含堆栈指针的重置值和所有异常处理程序的起始地址,也称为异常向量。第 39 页的图 11 显示了向量表中异常向量的顺序。每个向量的最低有效位必须为 1,表示异常处理程序是 Thumb 代码。

因此,LSb = 1 表示该向量指向的指令是Thumb指令。Cortex-M 内核仅支持Thumb指令集。编译器知道这一点,并自动使 LSb = 1。如果您以某种方式设法将其设为 0,则它将不起作用。