GD32的Makefile+启动文件+LD链接文件配置


看到一篇很好的文章附一下:
https://www.cnblogs.com/RegressionWorldLine/p/14819836.html

Makefile

对于Makefile没啥好说的,本质是继承预处理编译和汇编,一些不懂得都写在了注释里
需要更改的地方有:
TARGET
C_SOURCES
ASM_SOURCES
CPU FPU FLOAT-ABI
C_INCLUDES
LDSCRIPT
加密:@$(ENCRYPT_TOOL) $@ ./lppc_boot.xml ( B U I L D D I R ) / (BUILD_DIR)/ (BUILDDIR)/(TARGET)_encrypt.bin

# lppc_boot

TARGET = lppc_boot

# 判断当前系统是windows,mac还是linux

  
# DEBUG release

ifdef RELEASE

DEBUG = 0

else

DEBUG = 1

endif

# 优化等级

OPT = -O1

# 创建在build目录下

BUILD_DIR = build

# 包含文件

C_SOURCES =  \

${wildcard CMSIS/*.c}  \ 

${wildcard USER/*.c}   \

${wildcard protocol/*.c}  \

${wildcard protocol/support/*.c}  \

${wildcard Platform/*.c} \

#${wildcard applications/*.c}

  

# ASM sources 启动文件

ASM_SOURCES =  STARTUP/startup_gd32fl23x.s

# 编译工具链

PREFIX = arm-none-eabi-

# 工具链路径,已经加入环境变量则不需要定义GCC_PATH

ifdef GCC_PATH

CC = $(GCC_PATH)/$(PREFIX)gcc

AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp

CP = $(GCC_PATH)/$(PREFIX)objcopy

SZ = $(GCC_PATH)/$(PREFIX)size

else

CC = $(PREFIX)gcc

AS = $(PREFIX)gcc -x assembler-with-cpp

CP = $(PREFIX)objcopy

SZ = $(PREFIX)size

endif

# 编译hex和bin文件

HEX = $(CP) -O ihex

BIN = $(CP) -O binary -S

  

CPU = -mcpu=cortex-m23

#无浮点运算(硬件浮点)

#浮点运算处理方式

FPU =

FLOAT-ABI =

  

MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)

  

AS_DEFS =

  
  

C_DEFS =  

  
  

ifdef RELEASE

C_DEFS += -DRELEASE

endif

  
  

AS_INCLUDES =

  

# C includes -I代表在这个参数指定的目录下去寻找

C_INCLUDES =  \

-ICMSIS \

-IUSER \

-Iprotocol \

-Iprotocol/support \

-IPlatform \

#-Iapplications

  

# compile gcc flags

ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections

  

CFLAGS += $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections

  

ifeq ($(DEBUG), 1)

CFLAGS += -g -gdwarf-2

endif

  

# -M 生成文件关联的信息。包含目标文件所依赖的所有源代码

# -MMD 生成文件关联的信息。包含目标文件所依赖的所有源代码,但是它将忽略由#include造成的依赖关系,输出将导入到.d的文件里面

# -MF 指一个文件用于存放生成文件的关联信息,这些信息与-M或-MM是一样的,所以要与-M或-MM一起使用,否则会报错,

#将.o文件变为.d文件

CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"

  

# 链接ld地址

LDSCRIPT = FLASH_LINK/GD32FL233KBQx_FLASH.ld

  

# libraries

#map文件包含信息分为一下5大类

#1.Section Cross References:模块、段(入口)交叉引用

#2.Removing Unused input sections from the image:移除未调用模块

#3.Image Symbol Table:映射符号表

#4.Memory Map of the image:内存(映射)分布

#5.Image component sizes:存储组成大小

LIBS = -lc -lm -lnosys

LIBDIR =

LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections

  

# addprefix 将前缀加到name前面,将所有.c文件转换成.0,notdir去掉路径,sort去重复路径,dir取路径,与notdir相反

# vpath <pattern> <directories> 设置符合pattern的文件的搜索路径是directories

# % 匹配任何字符 $@  表示目标文件 $^  表示所有的依赖文件 $<  表示第一个依赖文件 $?  表示比目标还要新的依赖文件列表

OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))

vpath %.c $(sort $(dir $(C_SOURCES)))

# list of ASM program objects

OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))

vpath %.s $(sort $(dir $(ASM_SOURCES)))

#最终要生成elf,hex,bin文件

all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin

# | $(BUILD_DIR)标志是生成build这个目录,若以生成则忽略,将.s和.c转换成.o

$(BUILD_DIR)/%.o: %.c | $(BUILD_DIR)

    @echo compiling $@

    @$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@

  

$(BUILD_DIR)/%.o: %.s | $(BUILD_DIR)

    @echo assembling $@

    @$(AS) -c $(CFLAGS) $< -o $@

  

$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS)

    @echo linking

    @$(CC) $(OBJECTS) $(LDFLAGS) -o $@

    @$(SZ) $@

  

$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf

    @echo creating hex file $@

    @$(HEX) $< $@

#生产bin文件,同时生产加密文件bin

$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf

    @echo creating bin file $@

    @$(BIN) $< $@

# @$(ENCRYPT_TOOL) $@ ./lppc_boot.xml $(BUILD_DIR)/$(TARGET)_encrypt.bin  

  
  

$(BUILD_DIR):

    mkdir $@

  
  

clean:

    @echo delete $(BUILD_DIR)

    @-rm -fR $(BUILD_DIR)

  
  

-include $(wildcard $(BUILD_DIR)/*.d)

  

# *** EOF ***

启动文件

需要更改cotex-m23,中断向量表,若之后要加入boot自升级,需要多拷贝一次。
一些基本指令不理解的也有注释。

//.syntax [unified | divided] 。 作用是在汇编ARM汇编源时,指定按照怎样的语法规则进行汇编。

  .syntax unified

  .cpu cortex-m23

  .thumb

//.global 告诉编译器后续跟的是一个全局度可见的名字

.global  g_pfnVectors

.global  Default_Handler

// .word 表示与处理器有关的字长

/* start address for the initialization values of the .data section.

defined in linker script */

.word  _sidata

/* start address for the .data section. defined in linker script */

.word  _sdata

/* end address for the .data section. defined in linker script */

.word  _edata

/* start address for the .bss section. defined in linker script */

.word  _sbss

/* end address for the .bss section. defined in linker script */

.word  _ebss

/* stack used for SystemInit_ExtMemCtl; always internal RAM used */

  

//.section指示把代码划分成若干个段(Section),

//程序被操作系统加载执行时,每个段被加载到不同的地址

    .section  .text.Reset_Handler //这里Reset_Handler被分在了.text段

  .weak  Reset_Handler // 弱符号,如果其他地方未定义相同的强符号,则此处的符号将会被链接

  .type  Reset_Handler, %function //设置符号的属性,function意为函数

Reset_Handler:

  ldr   sp, =_estack     /* set stack pointer */

  

/* Copy the data segment initializers from flash to SRAM */

  ldr r0, =_sdata       ;从存储器中将_sdata的地址加载到寄存器r0

  ldr r1, =_edata       ;从存储器中将_edata的地址加载到寄存器r1

  ldr r2, =_sidata      ;从存储器中将_sidata的地址加载到寄存器r2

  movs r3, #0           ;赋予r3立即数0

  b LoopCopyDataInit    ;程序转移到LoopCopyDataInit处

  

CopyDataInit:;从FLASH中拷贝地址在sdata和edata之间的代码到SRAM中

  ldr r4, [r2, r3]      ;从地址r2+r3处读取一个字(32bit)到r4中

  str r4, [r0, r3]      ;把寄存器r4的值存储到存储器中地址为r0+r3地址处

  adds r3, r3, #4       ;r3 = r3 + 4

  

LoopCopyDataInit:

  adds r4, r0, r3       ;r4=r0+r3

  cmp r4, r1            ;计算r4 - r1,若小于0,标志位为0,反之为1

  bcc CopyDataInit      ;如果标志位为0(无借位)即r4<r1 CopyDataInit处

  

  ldr r0, =_sbootram    ;从存储器中将_sbootram的地址加载到寄存器r0

  ldr r1, =_ebootram    ;从存储器中将_ebootram的地址加载到寄存器r1

  ldr r2, =_sibootram   ;从存储器中将_sibootram的地址加载到寄存器r2

  movs r3, #0          

  b LoopFillZerobss   ;程序转移到LoopCopyDataInit2处

  

FillZerobss:

  str  r3, [r2]         ;把寄存器r3的值存储到存储器中地址为r2地址处

  adds r2, r2, #4       ;r2 = r2 + 4

  

LoopFillZerobss:

  cmp r2, r4            ;计算r2 - r4,若小于0,标志位为0,反之为1

  bcc FillZerobss       ;如果标志位为0(无借位)即r2<r4 跳到FillZerobss

  

/* Call the clock system initialization function.*/

//BL指令 将当前 指令 的地址存储到链接寄存器中,

//以便在执行完跳转 指令 后,能够返回到跳转前的地址

  bl  SystemInit        ;初始化时钟

/* Call static constructors */

  bl __libc_init_array;

/* Call the application's entry point.*/

  bl  main

  //LR寄存器一是用来保存子程序返回地址;二是当异常发生时,

  //LR中保存的值等于异常发生时PC的值减4(或者减2),

  //因此在各种异常模式下可以根据LR的值返回到异常发生前的相应位置继续执行。  

  bx  lr              ;bx lr的作用等同于mov  pc,lr即跳转到lr中存放的地址处。

.size  Reset_Handler, .-Reset_Handler       ;.size算符,汇编程序将回送分配给该变量的字节数

  

/**

 * @brief  This is the code that gets called when the processor receives an

 *         unexpected interrupt.  This simply enters an infinite loop, preserving

 *         the system state for examination by a debugger.

 * @param  None

 * @retval None

*/

    .section  .text.Default_Handler,"ax",%progbits

Default_Handler:

Infinite_Loop:

  b  Infinite_Loop

  .size  Default_Handler, .-Default_Handler

/******************************************************************************

*

* The minimal vector table for a Cortex M3. Note that the proper constructs

* must be placed on this to ensure that it ends up at physical address

* 0x0000.0000.

*

*******************************************************************************/

   .section  .isr_vector,"a",%progbits      ;.isr_vector就是中断向量表段

  .type  g_pfnVectors, %object              ;%object表示符号为数据对象.

  .size  g_pfnVectors, .-g_pfnVectors

  
  
  

g_pfnVectors:

  .word  _estack  

  .word  Reset_Handler                      ;复位中断

  

  .word  NMI_Handler                        ;不可屏蔽中断

  .word  HardFault_Handler                  ;硬件中断,内存溢出或者访问越界,堆栈溢出。增加堆栈的大小

  .word  0                                  ;访问了内存管理单元(MPU)定义的不合法的内存区域,比如向只读区域写入数据

  .word  0                                  ;在fetch指令、数据读写、fetch中断向量或中断时存储恢复寄存器栈情况下,检测到内存访问错误则产生BusFault。

  .word  0                                  ;检测到未定义指令或在存取内存时有未对齐。还可以通过软件配置是否检测到除数为0和其它未对齐内存访问也产生该异常,默认关闭,需要在工程初始化时配置。

  .word  0

  .word  0

  .word  0

  .word  0

  .word  SVC_Handler

  .word  0

  .word  0

  .word  PendSV_Handler

  .word  SysTick_Handler

  

    /* external interrupts handler */

  .word WWDGT_IRQHandler                      /* Window Watchdog interrupt                   */

  .word LVD_IRQHandler                    /* PVD through EXTI line                       */

  .word TAMPER_STAMP_IRQHandler     /* RTC tamper, timestamp                       */

  .word RTC_WKUP_IRQHandler                   /* RTC Wakeup interrupt                        */

  .word FMC_IRQHandler                      /* Flash memory                                */

  .word RCU_CTC_IRQHandler                        /* RCC global interrupt                        */

  .word EXTI0_IRQHandler                      /* EXTI Line 0 interrupt                       */

  .word EXTI1_IRQHandler                      /* EXTI Line 1 interrupt                       */

  .word EXTI2_IRQHandler                      /* EXTI Line 2 interrupt                       */

  .word EXTI3_IRQHandler                      /* EXTI Line 3interrupt                        */

  .word EXTI4_IRQHandler                      /* EXTI Line 4interrupt                        */

  .word DMA_Channel0_IRQHandler                   /* DMA1 Stream0                                */

  .word DMA_Channel1_IRQHandler                   /* DMA1 Stream1                                */

  .word DMA_Channel2_IRQHandler                   /* DMA1 Stream2                                */

  .word DMA_Channel3_IRQHandler                   /* DMA1 Stream3                                */

  .word DMA_Channel4_IRQHandler                   /* DMA1 Stream4                                */

  .word DMA_Channel5_IRQHandler                   /* DMA1 Stream5                                */

  .word DMA_Channel6_IRQHandler                   /* DMA1 Stream6                                */

  .word ADC_IRQHandler                      /* ADC1 and ADC2                               */

  .word USBD_HP_IRQHandler                  /* FDCAN1 Interrupt 0                          */

  .word USBD_LP_IRQHandler                  /* FDCAN2 Interrupt 0                          */

  .word TIMER1_IRQHandler                 /* FDCAN1 Interrupt 1                          */

  .word TIMER2_IRQHandler                 /* FDCAN2 Interrupt 1                          */

  .word TIMER8_IRQHandler                     /* EXTI Line[9:5] interrupts                   */

  .word TIMER11_IRQHandler                    /* TIM1 break interrupt                        */

  .word TIMER5_IRQHandler                     /* TIM1 update interrupt                       */

  .word TIMER6_IRQHandler               /* TIM1 trigger and commutation                */

  .word USART0_IRQHandler                     /* TIM1 capture / compare                      */

  .word USART1_IRQHandler                       /* TIM2 global interrupt                       */

  .word UART3_IRQHandler                        /* TIM3 global interrupt                       */

  .word UART4_IRQHandler                        /* TIM4 global interrupt                       */

  .word I2C0_EV_IRQHandler                    /* I2C1 event interrupt                        */

  .word I2C0_ER_IRQHandler                    /* I2C1 global error interrupt                 */

  .word I2C1_EV_IRQHandler                    /* I2C2 event interrupt                        */

  .word I2C1_ER_IRQHandler                    /* I2C2 global error interrupt                 */

  .word SPI0_IRQHandler                       /* SPI1 global interrupt                       */

  .word SPI1_IRQHandler                       /* SPI2 global interrupt                       */

  .word DAC_IRQHandler                      /* USART1 global interrupt                     */

  .word 0                     /* USART2 global interrupt                     */

  .word I2C2_EV_IRQHandler                      /* USART3 global interrupt                     */

  .word I2C2_ER_IRQHandler                  /* EXTI Line[15:10] interrupts                 */

  .word RTC_Alarm_IRQHandler                  /* RTC alarms (A and B)                        */

  .word USBD_WKUP_IRQHandler                                      /* Reserved                                    */

  .word EXTI5_9_IRQHandler              /* TIM8 and 12 break global                    */

  .word 0               /* TIM8 and 13 update global                   */

  .word 0         /* TIM8 and 14 trigger /commutation and global */

  .word 0                     /* TIM8 capture / compare                      */

  .word EXTI10_15_IRQHandler                  /* DMA1 Stream7                                */

  .word 0                         /* FMC global interrupt                        */

  .word 0                     /* SDMMC1 global interrupt                     */

  .word 0                       /* TIM5 global interrupt                       */

  .word 0                       /* SPI3 global interrupt                       */

  .word 0                       /* UART4 global interrupt                      */

  .word 0                       /* UART5 global interrupt                      */

  .word 0                   /* TIM6 global interrupt                       */

  .word DMAMUX_IRQHandler                       /* TIM7 global interrupt                       */

  .word CMP0_IRQHandler                   /* DMA2 Stream0 interrupt                      */

  .word CMP1_IRQHandler                   /* DMA2 Stream1 interrupt                      */

  .word I2C0_WKUP_IRQHandler                  /* DMA2 Stream2 interrupt                      */

  .word I2C2_WKUP_IRQHandler                  /* DMA2 Stream3 interrupt                      */

  .word USART0_WKUP_IRQHandler                  /* DMA2 Stream4 interrupt                      */

  .word LPUART_IRQHandler                         /* Ethernet global interrupt                   */

  .word CAU_IRQHandler                    /* Ethernet wakeup through EXTI                */

  .word TRNG_IRQHandler                   /* CAN2TX interrupts                           */

  .word SLCD_IRQHandler                                     /* Reserved                                    */

  .word USART1_WKUP_IRQHandler                                      /* Reserved                                    */

  .word I2C1_WKUP_IRQHandler                                      /* Reserved                                    */

  .word LPUART_WKUP_IRQHandler                                      /* Reserved                                    */

  .word LPTIMER_IRQHandler                  /* DMA2 Stream5 interrupt                      */

/*******************************************************************************

*

* Provide weak aliases for each Exception handler to the Default_Handler.

* As they are weak aliases, any function with the same name will override

* this definition.

*

*******************************************************************************/

  

  .weak NMI_Handler

  .thumb_set NMI_Handler,Default_Handler

  

  .weak HardFault_Handler

  .thumb_set HardFault_Handler,Default_Handler

  

  .weak SVC_Handler

  .thumb_set SVC_Handler,Default_Handler

  

  .weak PendSV_Handler

  .thumb_set PendSV_Handler,Default_Handler

  

  .weak SysTick_Handler

  .thumb_set SysTick_Handler,Default_Handler

  

  .weak WWDGT_IRQHandler

  .thumb_set WWDGT_IRQHandler,Default_Handler

  

  .weak LVD_IRQHandler

  .thumb_set LVD_IRQHandler,Default_Handler

  

  .weak TAMPER_STAMP_IRQHandler

  .thumb_set TAMPER_STAMP_IRQHandler,Default_Handler

  

  .weak RTC_WKUP_IRQHandler

  .thumb_set RTC_WKUP_IRQHandler,Default_Handler

  

  .weak FMC_IRQHandler

  .thumb_set FMC_IRQHandler,Default_Handler

  

  .weak RCU_CTC_IRQHandler

  .thumb_set RCU_CTC_IRQHandler,Default_Handler

  

  .weak EXTI0_IRQHandler

  .thumb_set EXTI0_IRQHandler,Default_Handler

  

  .weak EXTI1_IRQHandler

  .thumb_set EXTI1_IRQHandler,Default_Handler

  

  .weak EXTI2_IRQHandler

  .thumb_set EXTI2_IRQHandler,Default_Handler

  

  .weak EXTI3_IRQHandler

  .thumb_set EXTI3_IRQHandler,Default_Handler

  

  .weak EXTI4_IRQHandler

  .thumb_set EXTI4_IRQHandler,Default_Handler

  

  .weak DMA_Channel0_IRQHandler

  .thumb_set DMA_Channel0_IRQHandler,Default_Handler

  

  .weak DMA_Channel1_IRQHandler

  .thumb_set DMA_Channel1_IRQHandler,Default_Handler

  

  .weak DMA_Channel2_IRQHandler

  .thumb_set DMA_Channel2_IRQHandler,Default_Handler

  

  .weak DMA_Channel3_IRQHandler

  .thumb_set DMA_Channel3_IRQHandler,Default_Handler

  

  .weak DMA_Channel4_IRQHandler

  .thumb_set DMA_Channel4_IRQHandler,Default_Handler

  

  .weak DMA_Channel5_IRQHandler

  .thumb_set DMA_Channel5_IRQHandler,Default_Handler

  

  .weak DMA_Channel6_IRQHandler

  .thumb_set DMA_Channel6_IRQHandler,Default_Handler

  

  .weak ADC_IRQHandler

  .thumb_set ADC_IRQHandler,Default_Handler

  

  .weak USBD_HP_IRQHandler

  .thumb_set USBD_HP_IRQHandler,Default_Handler

  

  .weak USBD_LP_IRQHandler

  .thumb_set USBD_LP_IRQHandler,Default_Handler

  

  .weak TIMER1_IRQHandler

  .thumb_set TIMER1_IRQHandler,Default_Handler

  

  .weak TIMER2_IRQHandler

  .thumb_set TIMER2_IRQHandler,Default_Handler

  

  .weak TIMER8_IRQHandler

  .thumb_set TIMER8_IRQHandler,Default_Handler

  

  .weak TIMER11_IRQHandler

  .thumb_set TIMER11_IRQHandler,Default_Handler

  

  .weak TIMER5_IRQHandler

  .thumb_set TIMER5_IRQHandler,Default_Handler

  

  .weak TIMER6_IRQHandler

  .thumb_set TIMER6_IRQHandler,Default_Handler

  

  .weak USART0_IRQHandler

  .thumb_set USART0_IRQHandler,Default_Handler

  

  .weak USART1_IRQHandler

  .thumb_set USART1_IRQHandler,Default_Handler

  

  .weak UART3_IRQHandler

  .thumb_set UART3_IRQHandler,Default_Handler

  

  .weak UART4_IRQHandler

  .thumb_set UART4_IRQHandler,Default_Handler

  

  .weak I2C0_EV_IRQHandler

  .thumb_set I2C0_EV_IRQHandler,Default_Handler

  

  .weak I2C0_ER_IRQHandler

  .thumb_set I2C0_ER_IRQHandler,Default_Handler

  

  .weak I2C1_EV_IRQHandler

  .thumb_set I2C1_EV_IRQHandler,Default_Handler

  

  .weak I2C1_ER_IRQHandler

  .thumb_set I2C1_ER_IRQHandler,Default_Handler

  

  .weak SPI0_IRQHandler

  .thumb_set SPI0_IRQHandler,Default_Handler

  

  .weak SPI1_IRQHandler

  .thumb_set SPI1_IRQHandler,Default_Handler

  

  .weak DAC_IRQHandler

  .thumb_set DAC_IRQHandler,Default_Handler

  

  .weak I2C2_EV_IRQHandler

  .thumb_set I2C2_EV_IRQHandler,Default_Handler

  

  .weak I2C2_ER_IRQHandler

  .thumb_set I2C2_ER_IRQHandler,Default_Handler

  

  .weak RTC_Alarm_IRQHandler

  .thumb_set RTC_Alarm_IRQHandler,Default_Handler

  

  .weak USBD_WKUP_IRQHandler

  .thumb_set USBD_WKUP_IRQHandler,Default_Handler

  

  .weak EXTI5_9_IRQHandler

  .thumb_set EXTI5_9_IRQHandler,Default_Handler

  

  .weak EXTI10_15_IRQHandler

  .thumb_set EXTI10_15_IRQHandler,Default_Handler

  

  .weak DMAMUX_IRQHandler

  .thumb_set DMAMUX_IRQHandler,Default_Handler

  

  .weak CMP0_IRQHandler

  .thumb_set CMP0_IRQHandler,Default_Handler

  

  .weak CMP1_IRQHandler

  .thumb_set CMP1_IRQHandler,Default_Handler

  

  .weak I2C0_WKUP_IRQHandler

  .thumb_set I2C0_WKUP_IRQHandler,Default_Handler

  

  .weak I2C2_WKUP_IRQHandler

  .thumb_set I2C2_WKUP_IRQHandler,Default_Handler

  

  .weak USART0_WKUP_IRQHandler

  .thumb_set USART0_WKUP_IRQHandler,Default_Handler

  

  .weak LPUART_IRQHandler

  .thumb_set LPUART_IRQHandler,Default_Handler

  

  .weak CAU_IRQHandler

  .thumb_set CAU_IRQHandler,Default_Handler

  

  .weak TRNG_IRQHandler

  .thumb_set TRNG_IRQHandler,Default_Handler

  

  .weak SLCD_IRQHandler

  .thumb_set SLCD_IRQHandler,Default_Handler

  

  .weak USART1_WKUP_IRQHandler

  .thumb_set USART1_WKUP_IRQHandler,Default_Handler

  

  .weak I2C1_WKUP_IRQHandler

  .thumb_set I2C1_WKUP_IRQHandler,Default_Handler

  

  .weak LPUART_WKUP_IRQHandler

  .thumb_set LPUART_WKUP_IRQHandler,Default_Handler

  

  .weak LPTIMER_IRQHandler

  .thumb_set LPTIMER_IRQHandler,Default_Handler

  

  .weak SystemInit

  

/************************ (C) COPYRIGHT STMicroelectonics *****END OF FILE****/

链接文件

入口地址:ENTRY(SYMBOL),这里SYMBOL位Reset_Handler

/* Entry Point */
ENTRY(Reset_Handler)

定义内存

MEMORY 命令

脚本中以MEMORY命令定义了存储空间,其中以ORIGIN定义地址空间的起始地址,LENGTH定义地址空间的长度.NAME :存储区域的名字。(自己可以随意命名)
ATTR :定义该存储区域的属性。ATTR属性内可以出现以下7 个字符:
R 只读section
W 读/写section
X 可执行section
A 可分配的section
I 初始化了的section
L 同 I
! 不满足该字符之后的任何一个属性的section
ORIGIN :关键字,区域的开始地址,可简写成 org 或 o
LENGTH :关键字,区域的大小,可简写成 len 或 l

GD内存分配

  1. 设置RAM结束地址:起始地址为0x20000000,ram大小为24K,结束地址为0x20006000.
  2. 设置堆栈:由于使用的heap4,不使用标准库的malloc因此这里配置0x0,
    系统栈配置为0x600,1536字节,够用
    了。
/* Highest address of the user mode stack */
_estack = 0x20006000;    /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x0;      /* required amount of heap  */
_Min_Stack_Size = 0x600; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 24K
FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 128K
}

malloc的优缺点

为何使用heap4而不适用malloc进行内存分配,主要是通过heap4分配它有自带的首次适应算法和内存合并算法,同时它还能够反馈给我们更多的信息用于我们进行调试,在ozone上还能够看到内存块进行分析。
malloc的优缺点如下:
优点:

  1. 动态分配内存:malloc函数可以根据需要动态分配内存空间,可以根据程序的实际需求来分配合适大小的内存,提高程序的灵活性和效率。
  2. 可以根据需求释放内存:分配的内存可以通过free函数进行释放,可以在不需要该内存时及时释放,避免内存的浪费。
  3. 分配的内存可以在函数之间传递:通过malloc分配的内存可以在函数之间传递,可以在函数调用结束后,仍然保留分配的内存空间。
    缺点:
  4. 需要手动管理内存:使用malloc函数分配的内存需要手动释放,否则会造成内存泄漏,导致程序运行效率低下或者内存耗尽。
  5. 容易出现内存分配错误:如果使用不当,比如分配的内存大小不够或者释放的内存不正确,会导致程序出现错误,如内存读写错误、段错误等。
  6. 对内存的使用需要精确控制:使用malloc分配的内存需要精确控制大小和使用方式,否则容易导致内存溢出或者内存访问错误。

配置section段和符号

section和关键字

SECTIONS
{
       ...
      secname [start_ADDR] [(TYPE)] : [AT (LMA_ADDR)]
      { 
        contents 
      } [>REGION] [AT>LMA_REGION] [:PHDR HDR ...] [=FILLEXP]
      ...
}

[ ]内的内容是可选选项.
secname: 表示输出文件的 section 名,即输出文件中有哪些 section。
而contents就是描述输出文件的这个 section 内容从哪些输入文件的哪些 section 里抽取而来。
输出section名字必须符合输出文件格式要求,比如:a.out格式的文件只允许存在.text、.data和.bss section名。而有的格式只允许存在数字名字,那么此时应该用引号将所有名字内的数字组合在一起;另外,还有一些格式允许任何序列的字符存在于 section名字内,此时如果名字内包含特殊字符(比如空格、逗号等),那么需要用引号将其组合在一起.

TYPE:每个输出section都有一个类型,如果没有指定TYPE类型,那么链接器根据输出section引用的输入section的类型设置该输出section的类型。它可以为以下五种值

  • NOLOAD 该section在程序运行时,不被载入内存。
  • DSECT,COPY,INFO,OVERLAY :这些类型很少被使用,为了向后兼容才被保留下来。这种类型的section必须被标记为“不可加载的”,以便在程序运行不为它们分配内存。

AT( LAM_ADDR ):输出 section 的 LMA,默认情况下 LMA 等于 VMA,但可以通过关键字 AT() 指定 LMA。用关键字 AT()指定,括号内包含表达式,表达式的值用于设置LMA。如果不用AT()关键字,那么可用AT>LMA_REGION表达式设置指定该section加载地址的范围。这个属性主要用于构建ROM镜像。

[>REGION]:这个region就是前面说的MEMORY命令定义的位置信息,用于指定section在哪个memory执行,也就是VMA。如果不指定LMA,LMA = VMA。

KEEP 关键字
在链接命令行内使用了选项 -gc-sections 后,链接器可能将某些它认为没用的 section 过滤掉,此时就有必要强制让链接器保留一些特定的 section,可用 KEEP() 关键字达此目的。如 KEEP(* (.text)) 或 KEEP(SORT(*)(.text))。说的通俗易懂就是:防止被优化。

ALIGN 关键字
表示字节对齐, 如 “ . = ALIGN(4);”表示从该地址开始后面的存储进行4字节对齐。

LOADADDR()
进行地址设定

HIDDEN
通过赋值语句定义的符号是全局的,如果想定义一个只在本链接脚本中可见的符号,可以通过HIDDEN(symbol = expression)命令来定义,例如:
HIDDEN(start_of_data = 0x123456)
该命令类似C语言中在函数外定义一个static变量

PROVIDE_HIDDEN
该命令同PROVIDE,区别是PROVIDE定义的符号是全局,PROVIDE_HIDDEN定义的符号只在本脚本中可见

VMA 和 LMA

section包含两个地址:VMA(virtual memory address虚拟内存地址)和LMA(load memory address加载内存地址)。通常VMA和LMA是相同的。

  • VMA是执行输出文件时section所在的地址
  • LMA是加载输出文件时section所在的地址

要作为运行地址,首先PC指针要能在这个地址空间内跑动,所以这段地址空间必须是可随机寻址的,也就是说可以访问想要访问的地址,如RAM,NorFlash(Norflash带有SRAM接口,有足够的地址引脚来寻址,可以很容易地存取其内部的每一个字节);如果是NandFlash,则不行,因为NandFlash只能通过一个块一个块的读/写,不能做到随机寻址。

VMA和LMA大多数情况下是相等的,但也可以不相等。通常,当LMA地址空间不支持随机寻址,或者是嫌弃LMA地址空间的访问速度比较慢时(比如NorFlash速度比SDRAM慢),则会将VMA设置到RAM中,这时,VMA与LMA就不相等了。

例:NandFlash因为不能随机访问想要访问的每个地址,不能作为运行地址,所以这里想要把在NandFlash的代码复制到SDRAM中。这里除了代码中要加入复制模块外,还要在链接脚本中使NandFlash部分的VMA设为SDRAM地址。大多数情况下,是在起始代码中初始化时就将需要复制的部分复制的到VMA地址空间中。

还有一种情况就是当嵌入式系统中先都将代码和数据加载到了ROM中,此时的地址就是LMA,但是当开始运行之后,需要将data数据部分拷贝到RAM中,此时数据的地址就是VMA,本文最开始的链接脚本,就是把.data的LMA设置在ROM,VMA设置在RAM。

GD配置section段和符号

中断向量表段,代码段 的配置
例子:*(.text)描述语句指示ld将所有输入文件的.text段输出到输出文件的.text段,*匹配所有输入文件

 /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH//最终在flash中去执行

  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH

  /* Constant data goes into FLASH */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
  .ARM : {
    __exidx_start = .; // 设置变量
    *(.ARM.exidx*)
    __exidx_end = .;
  } >FLASH

.preinit_array段,.init_array 段,.fini_array 段

  .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 (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH

配置_sidata的地址给启动文件调用

_sidata = LOADADDR(.data);

配置数据段和BSS段以及 ._user_heap_stack :

RAM AT> FLASH表示在flash中加载,在ram中运行

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data :
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
  } >RAM AT> FLASH

  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM

  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM

清除

  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值