Arm Cortex-M3 FreeRTOS 加载启动

文章详细介绍了如何在QEMU环境中使用FreeRTOS操作系统启动STM32微控制器,重点在于Makefile中的链接过程和mps2_m3.ld链接脚本的作用。链接脚本定义了内存布局,如FLASH和RAM区域,以及入口点Reset_Handler。此外,还展示了如何通过objdump查看生成的可执行文件的各个section内容。
摘要由CSDN通过智能技术生成

接着QEMU+FreeRTOS+STM32+VS Code_阅后即奋的博客-CSDN博客,在QEMU中实现了STM32的启动,并在终端中打印了日志。

在那篇blog中讲到,启动点在下图①位置处。为什么?

 

还是看Makefile文件,并看其在终端的打印信息:

$(OUTPUT_DIR)/$(IMAGE): ./mps2_m3.ld $(OBJS_OUTPUT) Makefile
	@echo ""
	@echo ""
	@echo "--- Final linking ---"
	@echo ""
	$(LD) $(OBJS_OUTPUT) $(CFLAGS) -Xlinker --gc-sections -Xlinker -T ./mps2_m3.ld \
		-Xlinker -Map=$(OUTPUT_DIR)/RTOSDemo.map -specs=nano.specs \
		-specs=nosys.specs -specs=rdimon.specs -o $(OUTPUT_DIR)/$(IMAGE)
	$(SIZE) $(OUTPUT_DIR)/$(IMAGE)	
--- Final linking ---

arm-none-eabi-gcc ./output/tasks.o ./output/list.o ./output/queue.o ./output/timers.o ./output/event_groups.o ./output/stream_buffer.o ./output/heap_4.o ./output/port.o ./output/AbortDelay.o ./output/BlockQ.o ./output/blocktim.o ./output/countsem.o ./output/death.o ./output/dynamic.o ./output/EventGroupsDemo.o ./output/GenQTest.o ./output/integer.o ./output/IntQueue.o ./output/IntQueueTimer.o ./output/IntSemTest.o ./output/MessageBufferAMP.o ./output/MessageBufferDemo.o ./output/PollQ.o ./output/QPeek.o ./output/QueueOverwrite.o ./output/QueueSet.o ./output/QueueSetPolling.o ./output/recmutex.o ./output/semtest.o ./output/StaticAllocation.o ./output/StreamBufferDemo.o ./output/StreamBufferInterrupt.o ./output/TaskNotify.o ./output/TaskNotifyArray.o ./output/TimerDemo.o ./output/main.o ./output/main_blinky.o ./output/main_full.o ./output/startup_gcc.o ./output/printf-stdarg.o -I./../../../..//Source/include -I./../../../..//Source/portable/GCC/ARM_CM3 -I./../../../..//Demo/Common/include -I./../../../..//Demo/CORTEX_MPS2_QEMU_IAR_GCC -I./../../../..//Demo/CORTEX_MPS2_QEMU_IAR_GCC/CMSIS -nostartfiles -ffreestanding -mthumb -mcpu=cortex-m3 -Wall -Wextra -g3 -O0 -ffunction-sections -fdata-sections -MMD -MP -MF"output/RTOSDemo.out" -MT output/RTOSDemo.out -Xlinker --gc-sections -Xlinker -T ./mps2_m3.ld \
        -Xlinker -Map=./output/RTOSDemo.map -specs=nano.specs \
        -specs=nosys.specs -specs=rdimon.specs -o ./output/RTOSDemo.out
/home/mi/bin/arm-gnu-toolchain-12.2/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld: warning: ./output/RTOSDemo.out has a LOAD segment with RWX permissions
arm-none-eabi-size ./output/RTOSDemo.out
   text    data     bss     dec     hex filename
  17285     224   65491   83000   14438 ./output/RTOSDemo.out

在这个Makefile文件中,"-T mps2_m3.ld"是告诉链接器使用mps2_m3.ld文件作为链接脚本。在链接阶段,链接器将使用mps2_m3.ld文件中定义的内存布局和符号表等信息来生成最终的可执行文件。

当执行"make"命令时,Makefile文件将会编译所有的源文件,并将它们链接成一个名为"RTOSDemo.out"的可执行文件。在链接阶段,mps2_m3.ld文件将被自动加载并使用。

下面是mps2_m3.ld文件的信息,ld文件的语法这里不讲,可以参考:链接脚本 - 知乎

MEMORY
{
    FLASH (xr) : ORIGIN = 0x00000000, LENGTH = 4M /* to 0x00003FFF = 0x007FFFFF*/
    RAM (rw)  : ORIGIN = 0x20000000, LENGTH = 4M /* to 0x21FFFFFF = 0xFFFFFF */
}
ENTRY(Reset_Handler)

_Min_Heap_Size = 0x8 ;        /* Not used as building heap_4.c */
_Min_Stack_Size = 0x400 ;       /* Required amount of stack.  Used by main(), then re-used as the interrupt stack after the kernel starts. */
_estack = ORIGIN(RAM) + LENGTH(RAM);


SECTIONS
{
    .isr_vector :
    {
        __vector_table = .;
        KEEP(*(.isr_vector))
        . = ALIGN(4);
    } > FLASH

    .text :
    {
        *(.text)
        *(.rodata*)
        *(.constdata*)
        _etext = .;
        _sidata = .;
    } > FLASH

    .data :
    {
        . = ALIGN(8);
        _data = .;
        _sdata = .;
        *(vtable)
        *(.data)
        _edata = .;
    } > RAM

    .bss :
    {
        . = ALIGN(8);
        _bss = .;
        _sbss = .;
        *(.bss)
        _ebss = .;
    } > RAM

    .heap :
    {
        . = ALIGN(8);
        PROVIDE ( end = . );
        PROVIDE ( _end = . );
        _heap_bottom = .;
        . = . + _Min_Heap_Size;
        _heap_top = .;
        . = . + _Min_Stack_Size;
        . = ALIGN(8);
   } >RAM

   /* Set stack top to end of RAM, and stack limit move down by
    * size of stack_dummy section */
   __StackTop = ORIGIN(RAM) + LENGTH(RAM);
   __StackLimit = __StackTop - _Min_Stack_Size;
   PROVIDE(__stack = __StackTop);

  /* Check if data + heap + stack exceeds RAM limit */
  ASSERT(__StackLimit >= _heap_top, "region RAM overflowed with stack")

}

该文件定义了内存布局和各个节(section)的位置和大小。

首先,定义了两个内存区域:FLASH和RAM。FLASH是只读的,用于存储程序代码和只读数据,起始地址为0x00000000,大小为4M。RAM是可读写的,用于存储程序运行时的数据和堆栈,起始地址为0x20000000,大小也为4M。

接着,定义了程序的入口点为Reset_Handler

然后,定义了一些符号(symbol),包括最小堆大小(_Min_Heap_Size)、最小栈大小(_Min_Stack_Size)和栈顶(__StackTop)。其中,最小堆大小和最小栈大小是为了保证程序正常运行所需的最小内存空间,栈顶是指向RAM区域末尾的指针。

最后,定义了各个节的位置和大小。其中,.isr_vector节存放中断向量表,位于FLASH区域;.text节存放程序代码,也位于FLASH区域;.data节存放程序运行时的数据,位于RAM区域;.bss节存放未初始化的全局变量和静态变量,也位于RAM区域;.heap节存放堆空间,位于RAM区域;__StackTop和__StackLimit是栈顶和栈底的符号,用于在程序中获取栈的信息。最后,通过ASSERT宏检查数据、堆和栈的总大小是否超出了RAM区域的大小。

到这解释了为什么入口处是Reset_Handler函数。

使用objdump -h RTOSDemo.out命令(建议重定向到一个文本文件中去查看),可以看到各个section的内容,这里就只展示前10个吧(与前文讲的section分配是一致的):

RTOSDemo.out:     文件格式 elf32-little

节:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .isr_vector   00000078  00000000  00000000  00001000  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  1 .text         0000021b  00000078  00000078  00001078  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .text.xTaskCreateStatic 000000a4  00000294  00000294  00001294  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  3 .text.xTaskCreate 00000094  00000338  00000338  00001338  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  4 .text.prvInitialiseNewTask 00000108  000003cc  000003cc  000013cc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  5 .text.prvAddNewTaskToReadyList 00000124  000004d4  000004d4  000014d4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  6 .text.xTaskDelayUntil 000000dc  000005f8  000005f8  000015f8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  7 .text.vTaskStartScheduler 000000d0  000006d4  000006d4  000016d4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  8 .text.vTaskSuspendAll 0000001c  000007a4  000007a4  000017a4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  9 .text.xTaskResumeAll 000001f0  000007c0  000007c0  000017c0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 10 .text.xTaskGetTickCount 0000001c  000009b0  000009b0  000019b0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE

size命令也显示了分配的各个section的情况,dec和hex分别是以十进制和十六进制展示该文件的大小:

arm-none-eabi-size ./output/RTOSDemo.out
   text    data     bss     dec     hex filename
  17285     224   65491   83000   14438 ./output/RTOSDemo.out

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阅后即奋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值