0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

e² studio中链接脚本的修改指导

瑞萨MCU小百科 来源:瑞萨MCU小百科 2024-06-13 10:49 次阅读

程序编译的几个阶段

一般而言,程序编译经历下图四个阶段,链接是编译的最后一步,无论是在PC上编译代码,还是在PC上使用嵌入式gcc工具交叉编译嵌入式代码,编译过程都是如下几步。深入理解链接过程是嵌入式工程师必要掌握的能力!

677e0400-2483-11ef-91d2-92fbcf53809c.png

ld链接脚本的基础概念

链接过程是将各式各样的.o文件链接为一个文件的过程。链接脚本描述连接器如何将这些输入文件(.o)文件映射为一个输出文件的,并且定义了输出文件的memory layout。几乎所有的链接脚本都是在做这些事情。

下面给出一个简单的链接脚本实例,每行脚本都有相应的注解:

左右滑动查看完整内容

SECTIONS
{
  . = 0x10000; 
  .text : { *(.text) }
  . = 0x8000000;
  .bss : { *(.bss) }
}

上面提到的定位计数器就是点 ‘.

这个链接脚本文件(Linker Scripty),用于告诉链接器如何将不同的代码和数据段(sections)组合在一起形成可执行文件。下面我会解释其中的每一部分:

1. = 0x10000;

这行代码重新设置了定位计数器(location counter)的值为0x10000,即地址0x10000。

它告诉链接器在此处开始分配.text段的地址空间。

2.text : { *(.text) }

这行代码定义了一个.text段,并告诉链接器将所有名为.text的数据节(section)放入这个段中。

*(.text)表示将所有输入文件中的.text段合并到输出文件的.text段中。

3 . = 0x8000000;

这行代码重新设置了定位计数器的值为0x8000000,即地址0x8000000。

它告诉链接器在此处开始分配.data和.bss段的地址空间。

4 .data : { *(.data) }

这行代码定义了一个.data段,并告诉链接器将所有名为.data的数据节放入这个段中。

*(.data)表示将所有输入文件中的.data段合并到输出文件的.data段中。

5.bss : { *(.bss) }

这行代码定义了一个.bss段,并告诉链接器将所有名为.bss的数据节放入这个段中。

*(.bss)表示将所有输入文件中的.bss段合并到输出文件的.bss段中。

总体来说,这段链接脚本告诉链接器在特定的地址处分配.text、.data和.bss段,并将对应的数据节合并到这些段中。

链接脚本相关的概念

内存(Memory)

左右滑动查看完整内容

MEMORY
{
  name [(attr)] : ORIGIN = origin, LENGTH = len
…
}

注解:这里的“attr”只能由以下特性组成:

‘R’ Read-only section

‘W’ -- Read/write section

‘X’ -- Executable section

‘A’ -- Allocatable section

‘I’ -- Initialized section

‘L’ -- Same as ‘I’

‘!’ -- Invert the sense of any of the attributes that follow

左右滑动查看完整内容

/* Memories definition */
MEMORY
{
  RAM (xrw) : ORIGIN = 0x20000300, LENGTH = 36K
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
}

注解:

“xrw”表示“RAM”区是可读、可写和可执行的,且RAM 的起始地址为“0x20000300”,长度为36K。

“rx”表示“FLASH”区是可读和可执行的,FLASH的起始地址为“0x08000000”,长度为128K。

段(Section)

Section有loadable(可加载)和allocatable(可分配)两种类型。不可加载也不可分配的内存段,通常包含某些调试信息

loadable(可加载)是指:程序运行时,该段内容应该被加载到内存中。

allocatable(可分配)是指:该段的内容应该被预留出,但不应该加载任何别的内容(某些情况下,这些内存必须归零)。

“可加载”和“可分配”的section都有两个地址:“VMA”和“LMA”。

VMA(the virtual memory address):这是运行输出文件时,该section的地址。VMA是可选项,可以不设置。

LMA(load memory address):这是加载section时的地址。

在大多数情况下,这两个地址是相同的。当然也可以不相等,比如下面的例子就是LMA和VMA不同的案例:

数据段被加载到ROM中,然后在程序启动时复制到RAM中(通常用于初始化全局变量)。此时ROM地址就是LMA,RAM地址就是VMA。

语法:

左右滑动查看完整内容

SECTIONS
{
  section [address] [(type)] :
  {
    [AT(lma)]
    [ALIGN(section_align)  | ALIGN_WITH_INPUT]
    [SUBALIGN(subsection_align)]
    [constraint]
    {
      output-section-command 
      output-section-command 
      …
    } [>region] [AT>lma_region] [:phdr  :phdr ...] [=fillexp] [,]
...
}

大多数的段仅使用了上述的一部分属性。

示例:

左右滑动查看完整内容

/* Sections */ 
SECTIONS
{
  /* The startup code into "FLASH" Rom type memory */
  .isr_vector : 
  {
    . = ALIGN(4); 
    KEEP(*(.isr_vector)) /* Startup code */ 
    . = ALIGN(4); 
  } >FLASH


  /* Initialized data sections into "RAM" Ram type memory */
  .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
 
}

上述示例中“.isr_vector”的LMA与VMA是相等的。“.data”因为有“>RAM AT> FLASH”的修饰,表示.data段的VMA为RAM,LMA为FLASH。即.data段的内容会放在FLASH中,但是运行时,会加载到RAM中。

常用命令

ASSERT

语法:ASSERT(exp, message)

确保exp是非零值,如果为零,将以错误码的形式退出链接文件,并输出message。在必要的位置添加断言,可以清晰的定位问题。

左右滑动查看完整内容

/* The usage of ASSERT */ 
.test : 
{ 
  ASSERT ((_estack > (_Min_Stack_Size + _Min_Heap_Size)),"Error: There is an ERR occurred"); 
}

当示例中的“_estack”大于“_Min_Stack_Size + _Min_Heap_Size”时,就会打印“There is an ERR occurred”。

KEEP

用途:当链接器使用('--gc-sections')进行垃圾回收时,KEEP()可以使得被标记段的内容不被清除。

左右滑动查看完整内容

/* The startup code into "FLASH" Rom type memory */
.isr_vector : 
{
  . = ALIGN(4); 
  KEEP(*(.isr_vector)) /* Startup code */ 
  . = ALIGN(4); 
} >FLASH

指定“变量”的输出地址:

可以定义如下的memory,然后将“变量”存放于该memory,就能控制“变量”的输出地址。

左右滑动查看完整内容

/* Memories definition */
 
MEMORY 
{ 
  FW_RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x300 /* 0x20000000 ~ 0x200002FF */ 
  RAM (xrw) : ORIGIN = 0x20000300, LENGTH = 35K 
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K 
}

同时在c文件中,在定义“变量”时,添加如下对应的属性:

__attribute__((section(".FW_RAM"))) uint8_t key[8] = {0,1,2,3,4,5,6,7 };

变量将位于“0x20000000 ~ 0x200002FF”区域(如果仅仅只有key数组位于该区域,将从0x20000000开始存放,如果有多个变量存储于该区域,将按照编译的顺序,从0x20000000依次存放)。

指定“函数”的输出地址:

可以定义如下的memory和section,然后将“函数”存放于该section,就能控制“函数”的输出地址。

左右滑动查看完整内容

/* Memories definition */ 
MEMORY 
{ 
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x300 /* 0x08000000 ~ 0x080002FF */ 
  CG_FLASH (rx) : ORIGIN = 0x08000300, LENGTH = 0x134 /* 0x08000300 ~ 0x08000433 */ 
  RAM (xrw) : ORIGIN = 0x20000300, LENGTH = 0x900 /* 0x20000300 ~ 0x20001FFF */ 
}
 
SECTIONS
{
  …
  .SE_Call_Fun:
  {
     . = ALIGN(4); 
     . = . + 0x4; 
    *(.SE_Call_Fun) 
     . = ALIGN(4);
  } > CG_FLASH
  …
}

同时在c文件中, 在“函数”的实现部分,添加如下对应的属性:

__attribute__((section(".SE_Call_Fun"))) uint32_t call_fun(Callgate_Func_Type_t ftype, void *param)

函数“call_fun”将存放于0x08000304处(留意此处的位置计数器将产生0x04的内存间隙)。

指定“文件”输出地址:

可以定义如下的memory和section,然后将指定的文件存放于该section,就能控制“文件”的输出地址。

左右滑动查看完整内容

/* Memories definition */
 MEMORY 
{
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x300 /* 0x08000000 ~ 0x080002FF */ 
  FW_FLASH (rx) : ORIGIN = 0x08000434, LENGTH = 0x2BCC/* 0x08000434 ~ 0x08003000 */ 
  RAM (xrw) : ORIGIN = 0x20000300, LENGTH = 0x900 /* 0x20000300 ~ 0x20001FFF */ 
}
/* Sections */ 
SECTIONS 
{
  … 
  .main_section : 
  {
    . = ALIGN(4); 
    Core/Src/main.o(.text*) 
    . = ALIGN(4); 
  } >FLASH 
  … 
}

示例中将main.o指定到FLASH区域中;更改FLASH的地址或者main_section的LMA,就可以实现将特定文件指定到特定内存区域。

案例:RZ/N2L把 .text, .data, .bss段从ATCM改到SYSTEM_RAM

这里描述的RZ/N2L的内存分配:

左右滑动查看完整内容

67a1825e-2483-11ef-91d2-92fbcf53809c.png

长按可保存查看大图

把.text段从ATCM改到SYSTEM_RAM:

左右滑动查看完整内容

67da1bfa-2483-11ef-91d2-92fbcf53809c.png

长按可保存查看大图

把.data段从ATCM改到SYSTEM_RAM:

左右滑动查看完整内容

67fc3b5e-2483-11ef-91d2-92fbcf53809c.png

长按可保存查看大图

.bss段的改动也是类似的:

左右滑动查看完整内容

6831d1ba-2483-11ef-91d2-92fbcf53809c.png

长按可保存查看大图

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5056

    文章

    18950

    浏览量

    301479
  • 程序
    +关注

    关注

    115

    文章

    3753

    浏览量

    80709
  • 脚本
    +关注

    关注

    1

    文章

    385

    浏览量

    14802

原文标题:e² studio中链接脚本的修改指导(通用)

文章出处:【微信号:瑞萨MCU小百科,微信公众号:瑞萨MCU小百科】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    linux kernel通过修改链接脚本lds文件,如何在esp32的linker.lf文件实现?

    linux kernel通过修改链接脚本lds文件实现,请问如何在esp32的linker.lf文件实现? linux kernel实现过程:
    发表于 06-26 06:19

    请问不修改GNU链接脚本可以吗?

    我使用的是Psoc Creator 3.3 SP1的Pro模块。我不想修改GNU链接脚本或使用备用脚本。(更改起始地址和ROM大小)我应该怎么做,在这个时候,这是一个生成的文件。问候
    发表于 10-30 06:57

    链接脚本的相关资料下载

    文章目录链接脚本链接脚本的特点链接脚本的语法链接
    发表于 12-23 08:00

    MDK链接脚本的相关资料分享

    单片机编程使用 MDK时不可避免的要涉及到链接脚本文件。在链接脚本可以指定代码的存储布局,可以将代码段、只读数据段、可读写的数据段分别存放
    发表于 12-23 08:19

    RISC-V链接脚本的_stack_size的作用是什么

    使用的是CH32V103R8T6的开发板,代码是RT-Studio上下载的EVK的例程。对于例程链接脚本_stack_size变量的作
    发表于 11-16 11:28

    蜂鸟e203处理器开源代码恶的Makefile编译脚本和测试脚本怎么修改

    求助蜂鸟e203处理器开源代码恶的Makefile编译脚本和测试脚本怎么修改?有没有大佬指点一下,万分感谢
    发表于 08-12 06:52

    在Linux中生成新的gcc工具链后,如何使用链接脚本来生成能够被e203使用的.verilog文件?

    求在Linux中生成新的gcc工具链后,如何使用链接脚本来生成能够被e203使用的.verilog文件,希望老师能够提供较为详细的步骤指导,万分感谢!
    发表于 08-12 07:11

    LabVIEW编程指导脚本讲解

    LabVIEW编程指导脚本讲解,感兴趣的可以看看。
    发表于 06-01 17:28 34次下载

    LD链接脚本解析-STM32F4xx

    本篇文章主要围绕项目 STM32_RTOS_GUN 的链接脚本 STM32F417IG_FLASH.ld 进行分析,同时对编写链接脚本的方法进行相应的讲解,尽可能地做到通过阅读这篇文章
    发表于 11-26 10:51 12次下载
    LD<b class='flag-5'>链接</b><b class='flag-5'>脚本</b>解析-STM32F4xx

    【gcc编译优化系列】如何获取gcc默认的链接脚本

    elf文件这一步,我们需要使用到一个叫链接脚本的文件,这个文件主要描述了程序的ROM分布和RAM分布,它也直接决定了二进制文件的内容结构。 那么问题来了,当我们手上没有可用的链接
    的头像 发表于 07-11 09:15 3277次阅读

    e² studio创建lib文件及使用

    通过一个LED闪烁例程,简单介绍了创建库文件,使用库文件的流程。 工具 e 2 studio 复制以下链接到浏览器打开获取瑞萨e 2
    的头像 发表于 07-12 12:05 1097次阅读
    <b class='flag-5'>e</b>² <b class='flag-5'>studio</b>创建lib文件及使用

    关于STM32CubeIDE链接脚本的小问题

    电子发烧友网站提供《关于STM32CubeIDE链接脚本的小问题.pdf》资料免费下载
    发表于 09-20 11:25 0次下载
    关于STM32CubeIDE<b class='flag-5'>链接</b><b class='flag-5'>脚本</b>的小问题

    shell实例三(编写批量修改扩展名脚本)

    实现功能: 编写批量修改扩展名脚本,如批量将 txt 文件修改为 doc 文件 执行脚本时,需要给脚本添加位置参数
    的头像 发表于 11-09 09:35 634次阅读
    shell实例三(编写批量<b class='flag-5'>修改</b>扩展名<b class='flag-5'>脚本</b>)

    e² studiowaveform内存渲染工具应用

    e² studiowaveform内存渲染工具应用
    的头像 发表于 09-22 08:07 661次阅读
    <b class='flag-5'>e</b>² <b class='flag-5'>studio</b><b class='flag-5'>中</b>waveform内存渲染工具应用

    e² studio安装QE的流程介绍

    e² studio安装QE的流程介绍
    的头像 发表于 04-04 08:05 403次阅读
    在<b class='flag-5'>e</b>² <b class='flag-5'>studio</b><b class='flag-5'>中</b>安装QE的流程介绍