为什么这个函数确实以 1 的偏移量指向自身? [英] Why this function does point to itself with a offset of 1?

查看:16
本文介绍了为什么这个函数确实以 1 的偏移量指向自身?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to write a bare metal blink program for a Nucleo-64 Stm32F401re board using C. However while starting debugging for errors (it didn't blink yet) I found an odd adress for which I found no explanation. This is the output of the relevant part of the disassembly:

    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 函数本身在正确的地址上,但是通过在代码中使用它的名称作为指针,它进一步指向一个地址!对应的代码如下:

The Reset_Handler function itself is on the right adress but by using its name as pointer in the code it points one adress further! Here is the corresponding code:

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

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

And the Linker script I used which is basically the same used in most tutorials.

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.

So why the adress stored in the isr_vector_table is 08000009 and not 08000008? The only way I so far could change it to the right value was through hardcoding the value or defining a extra section for the Reset_Handler so I could use the adress as another extern value like the _stack_top.

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

Here are the commands I used for compilation as I don't know if they are necessary to find an answer:

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:

From the Programming Manual PM0214 of STM32F4:

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

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,则它将不起作用.

So, the LSb = 1 indicates that the instruction pointed by that vector is a Thumb instruction. Cortex-M cores support only Thumb instruction set. The compiler knows that, and makes LSb = 1 automatically. If you somehow manage to make it 0, it won't work.

这篇关于为什么这个函数确实以 1 的偏移量指向自身?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆