ld链接文件和startup文件分析和优化--基于RT1176

news/2024/12/5 7:33:31/

ld链接文件关系到程序的代码段数据段bss段及其用户自定义段的运行位置,ld文件中的各个段都会在main函数之前,从加载域拷贝到运行域中。本章将具体介绍如何修改ld和startup文件。

软件平台:VSCODE+GCC工具链

硬件平台:rt1176开发板

分析 MIMXRT1176xxxxx_cm7_flexspi_nor.ld 文件

官方原始文件如下:

/* Entry Point */
ENTRY(Reset_Handler)HEAP_SIZE  = DEFINED(__heap_size__)  ? __heap_size__  : 0x0400;
STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x0400;
RPMSG_SHMEM_SIZE = DEFINED(__use_shmem__) ? 0x2000 : 0;
VECTOR_RAM_SIZE = DEFINED(__ram_vector_table__) ? 0x00000400 : 0;
TEXT_SIZE = DEFINED(__use_flash64MB__) ? 0x03FBDC00 : 0x00FBDC00;
CORE1IMAGE_START = DEFINED(__use_flash64MB__) ? 0x33FC0000 : 0x30FC0000;/* Specify the memory areas */
MEMORY
{m_flash_config        (RX)  : ORIGIN = 0x30000400, LENGTH = 0x00000C00m_ivt                 (RX)  : ORIGIN = 0x30001000, LENGTH = 0x00001000m_interrupts          (RX)  : ORIGIN = 0x30002000, LENGTH = 0x00000400m_text                (RX)  : ORIGIN = 0x30002400, LENGTH = TEXT_SIZEm_qacode              (RX)  : ORIGIN = 0x00000000, LENGTH = 0x00040000m_data                (RW)  : ORIGIN = 0x20000000, LENGTH = 0x00040000m_data2               (RW)  : ORIGIN = 0x202C0000 + RPMSG_SHMEM_SIZE, LENGTH = 0x00080000 - RPMSG_SHMEM_SIZErpmsg_sh_mem          (RW)  : ORIGIN = 0x202C0000, LENGTH = RPMSG_SHMEM_SIZEm_core1_image         (RX)  : ORIGIN = CORE1IMAGE_START, LENGTH = 0x00040000
}/* Define output sections */
SECTIONS
{__NCACHE_REGION_START = ORIGIN(rpmsg_sh_mem);__NCACHE_REGION_SIZE  = LENGTH(rpmsg_sh_mem);.flash_config :{. = ALIGN(4);__FLASH_BASE = .;KEEP(* (.boot_hdr.conf))     /* flash config section */. = ALIGN(4);} > m_flash_configivt_begin = ORIGIN(m_flash_config) + LENGTH(m_flash_config);.ivt : AT(ivt_begin){. = ALIGN(4);KEEP(* (.boot_hdr.ivt))           /* ivt section */KEEP(* (.boot_hdr.boot_data))     /* boot section */KEEP(* (.boot_hdr.dcd_data))      /* dcd section */. = ALIGN(4);} > m_ivt/* section for storing the secondary core image */.core1_code :{. = ALIGN(4) ;KEEP (*(.core1_code))*(.core1_code*). = ALIGN(4) ;} > m_core1_image/* NOINIT section for rpmsg_sh_mem */.noinit_rpmsg_sh_mem (NOLOAD) : ALIGN(4){__RPMSG_SH_MEM_START__ = .;*(.noinit.$rpmsg_sh_mem*). = ALIGN(4) ;__RPMSG_SH_MEM_END__ = .;} > rpmsg_sh_mem/* The startup code goes first into internal RAM */.interrupts :{__VECTOR_TABLE = .;__Vectors = .;. = ALIGN(4);KEEP(*(.isr_vector))     /* Startup code */. = ALIGN(4);} > m_interrupts/* The program code and other data goes into internal RAM */.text :{. = ALIGN(4);*(.text)                 /* .text sections (code) */*(.text*)                /* .text* sections (code) */*(.rodata)               /* .rodata sections (constants, strings, etc.) */*(.rodata*)              /* .rodata* sections (constants, strings, etc.) */*(.glue_7)               /* glue arm to thumb code */*(.glue_7t)              /* glue thumb to arm code */*(.eh_frame)KEEP (*(.init))KEEP (*(.fini)). = ALIGN(4);} > m_text.ARM.extab :{*(.ARM.extab* .gnu.linkonce.armextab.*)} > m_text.ARM :{__exidx_start = .;*(.ARM.exidx*)__exidx_end = .;} > m_text.ctors :{__CTOR_LIST__ = .;/* gcc uses crtbegin.o to find the start ofthe constructors, so we make sure it isfirst.  Because this is a wildcard, itdoesn't matter if the user does notactually link against crtbegin.o; thelinker won't look for a file to match awildcard.  The wildcard also means that itdoesn't matter which directory crtbegin.ois in.  */KEEP (*crtbegin.o(.ctors))KEEP (*crtbegin?.o(.ctors))/* We don't want to include the .ctor section fromfrom the crtend.o file until after the sorted ctors.The .ctor section from the crtend file contains theend of ctors marker and it must be last */KEEP (*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors))KEEP (*(SORT(.ctors.*)))KEEP (*(.ctors))__CTOR_END__ = .;} > m_text.dtors :{__DTOR_LIST__ = .;KEEP (*crtbegin.o(.dtors))KEEP (*crtbegin?.o(.dtors))KEEP (*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors))KEEP (*(SORT(.dtors.*)))KEEP (*(.dtors))__DTOR_END__ = .;} > m_text.preinit_array :{PROVIDE_HIDDEN (__preinit_array_start = .);KEEP (*(.preinit_array*))PROVIDE_HIDDEN (__preinit_array_end = .);} > m_text.init_array :{PROVIDE_HIDDEN (__init_array_start = .);KEEP (*(SORT(.init_array.*)))KEEP (*(.init_array*))PROVIDE_HIDDEN (__init_array_end = .);} > m_text.fini_array :{PROVIDE_HIDDEN (__fini_array_start = .);KEEP (*(SORT(.fini_array.*)))KEEP (*(.fini_array*))PROVIDE_HIDDEN (__fini_array_end = .);} > m_text__etext = .;    /* define a global symbol at end of code */__DATA_ROM = .; /* Symbol is used by startup for data initialization */.interrupts_ram :{. = ALIGN(4);__VECTOR_RAM__ = .;__interrupts_ram_start__ = .; /* Create a global symbol at data start */*(.m_interrupts_ram)     /* This is a user defined section */. += VECTOR_RAM_SIZE;. = ALIGN(4);__interrupts_ram_end__ = .; /* Define a global symbol at data end */} > m_data__VECTOR_RAM = DEFINED(__ram_vector_table__) ? __VECTOR_RAM__ : ORIGIN(m_interrupts);__RAM_VECTOR_TABLE_SIZE_BYTES = DEFINED(__ram_vector_table__) ? (__interrupts_ram_end__ - __interrupts_ram_start__) : 0x0;.data : AT(__DATA_ROM){. = ALIGN(4);__DATA_RAM = .;__data_start__ = .;      /* create a global symbol at data start */*(m_usb_dma_init_data)*(.data)                 /* .data sections */*(.data*)                /* .data* sections */*(DataQuickAccess)       /* quick access data section */KEEP(*(.jcr*)). = ALIGN(4);__data_end__ = .;        /* define a global symbol at data end */} > m_data__ram_function_flash_start = __DATA_ROM + (__data_end__ - __data_start__); /* Symbol is used by startup for TCM data initialization */.ram_function : AT(__ram_function_flash_start){. = ALIGN(32);__ram_function_start__ = .;*(CodeQuickAccess). = ALIGN(128);__ram_function_end__ = .;} > m_qacode__NDATA_ROM = __ram_function_flash_start + (__ram_function_end__ - __ram_function_start__);.ncache.init : AT(__NDATA_ROM){__noncachedata_start__ = .;   /* create a global symbol at ncache data start */*(NonCacheable.init). = ALIGN(4);__noncachedata_init_end__ = .;   /* create a global symbol at initialized ncache data end */} > m_data. = __noncachedata_init_end__;.ncache :{*(NonCacheable). = ALIGN(4);__noncachedata_end__ = .;     /* define a global symbol at ncache data end */} > m_data__DATA_END = __NDATA_ROM + (__noncachedata_init_end__ - __noncachedata_start__);text_end = ORIGIN(m_text) + LENGTH(m_text);ASSERT(__DATA_END <= text_end, "region m_text overflowed with text and data")/* Uninitialized data section */.bss :{/* This is used by the startup in order to initialize the .bss section */. = ALIGN(4);__START_BSS = .;__bss_start__ = .;*(m_usb_dma_noninit_data)*(.bss)*(.bss*)*(COMMON). = ALIGN(4);__bss_end__ = .;__END_BSS = .;} > m_data.heap :{. = ALIGN(8);__end__ = .;PROVIDE(end = .);__HeapBase = .;. += HEAP_SIZE;__HeapLimit = .;__heap_limit = .; /* Add for _sbrk */} > m_data.stack :{. = ALIGN(8);. += STACK_SIZE;} > m_data/* Initializes stack on the end of block */__StackTop   = ORIGIN(m_data) + LENGTH(m_data);__StackLimit = __StackTop - STACK_SIZE;PROVIDE(__stack = __StackTop);.ARM.attributes 0 : { *(.ARM.attributes) }ASSERT(__StackLimit >= __HeapLimit, "region m_data overflowed with stack and heap")
}

从官方默认分散加载文件中,我们可以看到 text段(代码段),rodata段(只读段)运行域是在Flash中的,我们都知道rom的速度远远小于ram的,所以尽量将使用频繁的代码和变量拷贝到ram中运行。修改如下(展示部分):

    /* Specify the memory areas */MEMORY{m_flash_config        (RX)  : ORIGIN = 0x30000400, LENGTH = 0x00000C00m_ivt                 (RX)  : ORIGIN = 0x30001000, LENGTH = 0x00001000m_interrupts          (RX)  : ORIGIN = 0x30002000, LENGTH = 0x00000400m_rom_info            (RX)  : ORIGIN = 0x30002400, LENGTH = 0x00000400  /*用户信息,产品型号,版本等*/m_text                (RX)  : ORIGIN = 0x30002800, LENGTH = 0x007fdc00m_ram_interrupts      (RX)  : ORIGIN = 0x00000000, LENGTH = 0x00000400m_itcm_text           (XRW)  : ORIGIN = 0x00000400, LENGTH = 0x00037c00m_data                (XRW)  : ORIGIN = 0x20000000, LENGTH = 0x00048000m_ocram1              (XRW)  : ORIGIN = 0x20240000, LENGTH = 0x00080000m_ocram2              (XRW)  : ORIGIN = 0x202C0000, LENGTH = 0x00080000m_sdram               (XRW)  : ORIGIN = 0x80000000, LENGTH = 0x04000000}rom_info_begin = ORIGIN(m_rom_info);.rom_info : AT(rom_info_begin)  {. = ALIGN(4);/*用户信息段*/KEEP(* (.rom_info))           . = ALIGN(4);} >m_rom_info/*程序代码和其他部分数据存放在.text段中*//* The program code and other data goes into internal flash */.text :{. = ALIGN(4);__TEXT_START = .;  /*text段 起始地址*/*(.text) *(.reset) /*系统启动会先进这个函数,必须链接到ROM不能到RAM*/*(.text.SystemInit)*(.text.SystemInitHook)*crti.o(.text*)*crt0.o(.text*)*crtbegin.o(.text*)*crtend.o(.text*)*crtn.o(.text*)*(.glue_7)               *(.glue_7t)             *(.eh_frame)/* KEEP() 的作用是当启用连接器的--gc-sections垃圾回收选项时,这部分不能被回收 */KEEP (*(.init))KEEP (*(.fini)). = ALIGN(4);} > m_text.other_text :{. = ALIGN(4); _text_itcm_start_ = .;*(.other)*(.text.*) /* .rodata sections (constants, strings, etc.) 常量,字符串等*/*(.rodata)         *(.rodata*)     _text_itcm_end_ = .;. = ALIGN(4);} >m_itcm_text AT>m_text_text_load_start = LOADADDR(.other_text);  /*加载地址*/      

除此之外,还需要启动代码,将Reset_Handler和其他中断函数分为两个段(命名为reset和other段),分别链接到不同位置(ROMRAM中)

/* Reset Handler */.section .reset, "x".thumb_func.align 2.globl   Reset_Handler.weak    Reset_Handler.type    Reset_Handler, %function
Reset_Handler:cpsid   i               /* Mask interrupts */.equ    VTOR, 0xE000ED08ldr     r0, =VTORldr     r1, =__isr_vectorstr     r1, [r0]ldr     r2, [r1]msr     msp, r2.......pool.size Reset_Handler, . - Reset_Handler/*下面为 other段*/.section .other, "x".align  1.thumb_func.weak DefaultISR.type DefaultISR, %function
DefaultISR:b DefaultISR.size DefaultISR, . - DefaultISR ......

这时候我们编译代码,然后查阅map会发现当前大部分代码段已经链接到itcm中了

请添加图片描述
请添加图片描述
请添加图片描述

这样就算完了吗?如果你是修改keil的链接脚本scf文件,那么做到这里直接烧录程序就行了,因为剩下的拷贝交给__main来完成,但是我们用的是gcc,拷贝代码需要自己来写。这段拷贝代码需要在main函数之前完成,我们可以在startup_MIMXRT1176_cm7.s启动代码中用汇编语言写拷贝函数,也可以在SystemInitHook钩子函数中用C语言写拷贝函数。这里就拿代码段拷贝到itcm举例:

    /*将代码段拷贝到 itcm*/ldr    r1, =_text_load_startldr    r2, =_text_itcm_start_ldr    r3, =_text_itcm_end_
.LC_text_copy_start:cmp     r2, r3ittt    ltldrlt   r0, [r1], #4strlt   r0, [r2], #4blt    .LC_text_copy_start  
void SystemInitHook (void) 
{  uint32_t startAddr; /* Address of the source memory. */uint32_t endAddr;   /* End of copied memory. */uint32_t destAddr;  //加载地址(flash)/*******************text拷贝************************/extern uint32_t _text_itcm_start_;extern uint32_t _text_itcm_end_;extern uint32_t _text_load_start;startAddr = (uint32_t)&_text_itcm_start_;endAddr   = (uint32_t)&_text_itcm_end_;destAddr  = (uint32_t)&_text_load_start;while(startAddr < endAddr){/* Copy one byte. */*((uint8_t *)startAddr) = *((uint8_t *)destAddr) ;/* Increment the destination and source pointers. */destAddr++;startAddr++;}
}

http://www.ppmy.cn/news/1042097.html

相关文章

第一章 初识Linux(含VMware安装Ubuntu、CentOS、Windows、FinalShell、快照)

目录 一、 课程的介绍  1.为什么要学习Linux  2.课程的安排  3.如何学习Linux 二、操作系统概述  1.学习目标  2.计算机的硬件和软件  3.什么是操作系统  4.常见的操作系统  5.本小节的总结 三、初识Linux  1.学习目标  2.Linux的诞生  3.Linux的内核  …

Node.js学习笔记-05

10、测试 测试包含单元测试、性能测试、安全测试和功能测试等几个方面&#xff0c;本章将从Node实践的角度来介绍单元测试和性能测试。 10.1 单元测试 10.1.1 单元测试的意义 开发者自测。对于开发者而言&#xff0c;不仅要编写单元测试&#xff0c;还应当编写可测试代码。…

什么是卷积神经网络

目录 什么是卷积神经网络 全链接相对笨重&#xff1a;大胖子​编辑 ​编辑 参数众多&#xff1a;容易造成过拟合 ​编辑 卷积核&#xff1a;进行图像特征提取&#xff0c;源于卷积原理&#xff1a;求相交面积 卷积的作用 卷积的意义 ​编辑 通过卷积核减少参数 深度卷积…

解决无法访问 Github 问题

GitHub作为程序员访问最频繁的网站&#xff0c;程序员们经常需要访问 Github找开源项目、学习新框架、管理自己的个人开源项目等等。 github加速器 因为GitHub属于国外的网站&#xff0c;直接访问的话&#xff0c;速度非常慢&#xff0c;甚至访问不了&#xff0c; 今天给大家…

【Lua语法】算术、条件、逻辑、位、三目运算符

1.算术运算符 加减乘除取余&#xff1a; - * / % Lua中独有的&#xff1a;幂运算 ^ 注意&#xff1a; 1.Lua中没有自增自减(、–)&#xff0c;也没有复合运算符(、-) 2.Lua中字符串可以进行算术运算符操作&#xff0c;会自动转成number 如&#xff1a;“10.3” 1 结果为11.3…

Java实现postgre数据库每日定时自动备份

前提&#xff1a;该备份仅为同数据库不同schema备份 假设需要备份的数据库为test&#xff0c;schema为public。代码如下 public void backupAllTables() {log.info("备份全表开始执行" System.currentTimeMillis());String origScheme1 "public";String…

统计XML标注文件中各标注类别的标签数量

目标检测任务重&#xff0c;担心数据集中各标签类别不均衡&#xff0c;想统计XML标注文件中各标注类别的标签数量&#xff0c;可以使用以下脚本&#xff1a; import os import glob import xml.etree.ElementTree as etdef count_labels(source_dir):file_list glob.glob(os.…

使用GEWE框架进行个人微信收藏夹及标签管理(标签篇)适用于微信群管、社群管理

友情链接 geweapi.com 点击即可访问&#xff01; 添加标签 简要描述&#xff1a; 添加自定义标签 注意[name] 请求URL&#xff1a; http://域名地址/api/label/add 请求方式&#xff1a; POST 请求头&#xff1a; Content-Type&#xff1a;application/json 参数&#…