我在互联网上发现了一个启动手机皮层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
相同吗? copy_data()
函数在程序中做了什么?提前谢谢。
答案 0 :(得分:2)
链接描述文件指示链接器将数据放在闪存中,但链接代码就像数据在ram中一样。在启动代码中,数据然后从数据加载的地址(闪存)复制到数据应该是的地址(RAM)。
答案 1 :(得分:1)
copy_data()
将记忆从起始地址__data_load
复制到从__data_start
到__data_end
因此,复制的总尺寸为__data_end
- __data_start
。
当然,您已经在__data_load
处获得了数据。程序将它从FLASH复制到SRAM,在那里可以根据需要进行读写。
答案 2 :(得分:1)
我们在嵌入式代码中存在问题。存储选项是非易失性的,但不可修改(闪存/ ROM等)或易变的可修改存储。 'data'是初始化的非零任意值,可以修改(相对于const
或rodata
)。如何安排?
将数据副本放入闪存或ROM中。然后将该数据复制到RAM中,在RAM中读取和写入数据。
我的问题是在copy_data()函数中为什么我们需要将__data_load的地址分配给指针* src?是__data_load = LOADADDR(.data);与__data_start相同。 copy_data()函数在程序中做了什么?
copy_data()
是解决上述问题的方法。它从闪存(加载位置)获取内存并将其复制到RAM。虚拟寻址可以存在类似的二分法。在启用MMU之前,您需要在哪里安排物理地址和虚拟地址内容。链接器文档通常将运行/ RAM位置称为“VADDR”。
使用OS或某些ROM引导加载程序,您可以从磁盘/ MMC(NAND闪存)加载到RAM,并能够绕过copy_data()
。只有在您的代码直接从非易失性设备运行时才需要它。将整个图像从闪存复制到RAM通常会更快更简单。这当然取决于资源。 RAM的读访问通常比闪存更快。这将取决于您的系统。