代码之家  ›  专栏  ›  技术社区  ›  user8540390

如何编写C++中的简单启动代码?

  •  2
  • user8540390  · 技术社区  · 6 年前

    我在互联网上找到了一个arm cortex m内核的启动代码,并使用了这些源代码,但我对源代码中的某个函数有一些疑问,我将在这里粘贴代码和相应的链接器脚本。

    // very simple startup code with definition of handlers for all cortex-m cores
    
    // location of these variables is defined in linker script
    extern unsigned __data_load;
    
    extern unsigned __data_start;
    extern unsigned __data_end;
    
    extern unsigned __bss_start;
    extern unsigned __bss_end;
    
    extern unsigned __heap_start;
    
    extern unsigned __init_array_start;
    extern unsigned __init_array_end;
    
    extern unsigned __fini_array_start;
    extern unsigned __fini_array_end;
    
    // main application
    extern void main_app();
    
    void copy_data() {
        unsigned *src = &__data_load;
        unsigned *dst = &__data_start;
        while (dst < &__data_end) {
            *dst++ = *src++;
        }
    }
    
    void zero_bss() {
        unsigned *dst = &__bss_start;
        while (dst < &__bss_end) {
            *dst++ = 0;
        }
    }
    
    void fill_heap(unsigned fill=0x55555555) {
        unsigned *dst = &__heap_start;
        register unsigned *msp_reg;
        __asm__("mrs %0, msp\n" : "=r" (msp_reg) );
        while (dst < msp_reg) {
            *dst++ = fill;
        }
    }
    
    void call_init_array() {
        unsigned *tbl = &__init_array_start;
        while (tbl < &__init_array_end) {
            ((void (*)())*tbl++)();
        }
    }
    
    void call_fini_array() {
        unsigned *tbl = &__fini_array_start;
        while (tbl < &__fini_array_end) {
            ((void (*)())*tbl++)();
        }
    }
    
    // reset handler
    void RESET_handler() {
        copy_data();
        zero_bss();
        fill_heap();
        call_init_array();
        // run application
        main_app();
        // call destructors for static instances
        call_fini_array();
        // stop
        while (true);
    }
    

    SECTIONS {
        . = ORIGIN(FLASH);
        .text : {
            KEEP(*(.stack))
            KEEP(*(.vectors))
            KEEP(*(.vectors*))
            KEEP(*(.text))
            . = ALIGN(4);
            *(.text*)
            . = ALIGN(4);
            KEEP(*(.rodata))
            *(.rodata*)
            . = ALIGN(4);
        } >FLASH
    
        .init_array ALIGN(4): {
            __init_array_start = .;
            KEEP(*(.init_array))
            __init_array_end = .;
        } >FLASH
    
        .fini_array ALIGN(4): {
            __fini_array_start = .;
            KEEP(*(.fini_array))
            __fini_array_end = .;
        } >FLASH
    }
    
    SECTIONS {
        __stacktop = ORIGIN(SRAM) + LENGTH(SRAM);
        __data_load = LOADADDR(.data);
        . = ORIGIN(SRAM);
    
        .data ALIGN(4) : {
            __data_start = .;
            *(.data)
            *(.data*)
            . = ALIGN(4);
            __data_end = .;
        } >SRAM AT >FLASH
    
        .bss ALIGN(4) (NOLOAD) : {
            __bss_start = .;
            *(.bss)
            *(.bss*)
            . = ALIGN(4);
            __bss_end = .;
            *(.noinit)
            *(.noinit*)
        } >SRAM
    
        . = ALIGN(4);
        __heap_start = .;
    }
    

    我的问题是 copy_data() 函数为什么我们需要分配 __data_load 指向指针 *src __data_load = LOADADDR(.data); 与相同 __data_start 复制数据() 在程序中做什么?提前谢谢。

    3 回复  |  直到 6 年前
        1
  •  2
  •   Goswin von Brederlow    6 年前

    链接器脚本指示链接器将数据放在flash中,但将代码链接为ram中的数据。在启动代码中,数据从数据加载的地址(flash)复制到数据应该是的地址(RAM)。

        2
  •  1
  •   Attersson    6 年前

    copy_data() __data_load 进入地址范围从 __data_start __data_end

    __数据\u结束 - __数据\u启动 .

    当然你已经有了 __数据加载 . 程序将它从FLASH复制到SRAM,在那里可以根据需要进行读写。

        3
  •  1
  •   artless noise    6 年前

    const rodata ). 如何安排?

    数据的副本被放入闪存或ROM中,然后这些数据被复制到RAM中,在RAM中进行读写。


    我的问题是在copy\u data()函数中,为什么需要将\u data\u load的地址赋给指针*src?Is \uuu data \u load=LOADADDR(.data);与\uu data \u start相同。copy_data()函数在程序中做什么?

    copy_data() 是解决上述问题的方法。它从flash(加载位置)获取内存并将其复制到RAM。虚拟寻址也存在类似的二分法。在启用MMU之前,需要将物理地址和虚拟地址内容安排为相同。链接器文档通常将run/RAM位置称为“VADDR”。

    复制数据()