GD32的Makefile+启动文件+LD链接文件配置 您所在的位置:网站首页 gcc编译链接map文件分析 GD32的Makefile+启动文件+LD链接文件配置

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

2024-07-18 00:28| 来源: 网络整理| 查看: 265

GD32的Makefile+启动文件+LD链接文件配置 Makefile启动文件链接文件定义内存MEMORY 命令GD内存分配malloc的优缺点 配置section段和符号section和关键字VMA 和 LMA GD配置section段和符号 看到一篇很好的文章附一下: 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)/ (BUILDD​IR)/(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 # % 匹配任何字符 $@ 表示目标文件 $^ 表示所有的依赖文件 $< 表示第一个依赖文件 $? 表示比目标还要新的依赖文件列表 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 $( ... 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) }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有