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

Why this function does point to itself with a offset of 1?

我正在尝试使用 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.

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) {
        
    } 

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

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) }
        
    
    
}

那么为什么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

来自STM32F4的编程手册PM0214:

Vector table
The vector table contains the reset value of the stack pointer, and the start addresses, also called exception vectors, for all exception handlers. Figure 11 on page 39 shows the order of the exception vectors in the vector table. The least-significant bit of each vector must be 1, indicating that the exception handler is Thumb code.

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