0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

e2 studio中鏈接腳本的修改指導(dǎo)

瑞薩MCU小百科 ? 來源:瑞薩MCU小百科 ? 2024-06-13 10:49 ? 次閱讀

程序編譯的幾個(gè)階段

一般而言,程序編譯經(jīng)歷下圖四個(gè)階段,鏈接是編譯的最后一步,無論是在PC上編譯代碼,還是在PC上使用嵌入式gcc工具交叉編譯嵌入式代碼,編譯過程都是如下幾步。深入理解鏈接過程是嵌入式工程師必要掌握的能力!

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

ld鏈接腳本的基礎(chǔ)概念

鏈接過程是將各式各樣的.o文件鏈接為一個(gè)文件的過程。鏈接腳本描述連接器如何將這些輸入文件(.o)文件映射為一個(gè)輸出文件的,并且定義了輸出文件的memory layout。幾乎所有的鏈接腳本都是在做這些事情。

下面給出一個(gè)簡單的鏈接腳本實(shí)例,每行腳本都有相應(yīng)的注解:

左右滑動(dòng)查看完整內(nèi)容

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

上面提到的定位計(jì)數(shù)器就是點(diǎn) ‘.

這個(gè)鏈接腳本文件(Linker Scripty),用于告訴鏈接器如何將不同的代碼和數(shù)據(jù)段(sections)組合在一起形成可執(zhí)行文件。下面我會(huì)解釋其中的每一部分:

1. = 0x10000;

這行代碼重新設(shè)置了定位計(jì)數(shù)器(location counter)的值為0x10000,即地址0x10000。

它告訴鏈接器在此處開始分配.text段的地址空間。

2.text : { *(.text) }

這行代碼定義了一個(gè).text段,并告訴鏈接器將所有名為.text的數(shù)據(jù)節(jié)(section)放入這個(gè)段中。

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

3 . = 0x8000000;

這行代碼重新設(shè)置了定位計(jì)數(shù)器的值為0x8000000,即地址0x8000000。

它告訴鏈接器在此處開始分配.data和.bss段的地址空間。

4 .data : { *(.data) }

這行代碼定義了一個(gè).data段,并告訴鏈接器將所有名為.data的數(shù)據(jù)節(jié)放入這個(gè)段中。

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

5.bss : { *(.bss) }

這行代碼定義了一個(gè).bss段,并告訴鏈接器將所有名為.bss的數(shù)據(jù)節(jié)放入這個(gè)段中。

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

總體來說,這段鏈接腳本告訴鏈接器在特定的地址處分配.text、.data和.bss段,并將對應(yīng)的數(shù)據(jù)節(jié)合并到這些段中。

鏈接腳本相關(guān)的概念

內(nèi)存(Memory)

左右滑動(dòng)查看完整內(nèi)容

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

左右滑動(dòng)查看完整內(nèi)容

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

注解:

“xrw”表示“RAM”區(qū)是可讀、可寫和可執(zhí)行的,且RAM 的起始地址為“0x20000300”,長度為36K。

“rx”表示“FLASH”區(qū)是可讀和可執(zhí)行的,F(xiàn)LASH的起始地址為“0x08000000”,長度為128K。

段(Section)

Section有l(wèi)oadable(可加載)和allocatable(可分配)兩種類型。不可加載也不可分配的內(nèi)存段,通常包含某些調(diào)試信息。

loadable(可加載)是指:程序運(yùn)行時(shí),該段內(nèi)容應(yīng)該被加載到內(nèi)存中。

allocatable(可分配)是指:該段的內(nèi)容應(yīng)該被預(yù)留出,但不應(yīng)該加載任何別的內(nèi)容(某些情況下,這些內(nèi)存必須歸零)。

“可加載”和“可分配”的section都有兩個(gè)地址:“VMA”和“LMA”。

VMA(the virtual memory address):這是運(yùn)行輸出文件時(shí),該section的地址。VMA是可選項(xiàng),可以不設(shè)置。

LMA(load memory address):這是加載section時(shí)的地址。

在大多數(shù)情況下,這兩個(gè)地址是相同的。當(dāng)然也可以不相等,比如下面的例子就是LMA和VMA不同的案例:

數(shù)據(jù)段被加載到ROM中,然后在程序啟動(dòng)時(shí)復(fù)制到RAM中(通常用于初始化全局變量)。此時(shí)ROM地址就是LMA,RAM地址就是VMA。

語法:

左右滑動(dòng)查看完整內(nèi)容

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] [,]
...
}

大多數(shù)的段僅使用了上述的一部分屬性。

示例:

左右滑動(dòng)查看完整內(nèi)容

/* 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”因?yàn)橛小?RAM AT> FLASH”的修飾,表示.data段的VMA為RAM,LMA為FLASH。即.data段的內(nèi)容會(huì)放在FLASH中,但是運(yùn)行時(shí),會(huì)加載到RAM中。

常用命令

ASSERT

語法:ASSERT(exp, message)

確保exp是非零值,如果為零,將以錯(cuò)誤碼的形式退出鏈接文件,并輸出message。在必要的位置添加斷言,可以清晰的定位問題。

左右滑動(dòng)查看完整內(nèi)容

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

當(dāng)示例中的“_estack”大于“_Min_Stack_Size + _Min_Heap_Size”時(shí),就會(huì)打印“There is an ERR occurred”。

KEEP

用途:當(dāng)鏈接器使用('--gc-sections')進(jìn)行垃圾回收時(shí),KEEP()可以使得被標(biāo)記段的內(nèi)容不被清除。

左右滑動(dòng)查看完整內(nèi)容

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

指定“變量”的輸出地址:

可以定義如下的memory,然后將“變量”存放于該memory,就能控制“變量”的輸出地址。

左右滑動(dòng)查看完整內(nèi)容

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

同時(shí)在c文件中,在定義“變量”時(shí),添加如下對應(yīng)的屬性:

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

變量將位于“0x20000000 ~ 0x200002FF”區(qū)域(如果僅僅只有key數(shù)組位于該區(qū)域,將從0x20000000開始存放,如果有多個(gè)變量存儲于該區(qū)域,將按照編譯的順序,從0x20000000依次存放)。

指定“函數(shù)”的輸出地址:

可以定義如下的memory和section,然后將“函數(shù)”存放于該section,就能控制“函數(shù)”的輸出地址。

左右滑動(dòng)查看完整內(nèi)容

/* 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
  …
}

同時(shí)在c文件中, 在“函數(shù)”的實(shí)現(xiàn)部分,添加如下對應(yīng)的屬性:

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

函數(shù)“call_fun”將存放于0x08000304處(留意此處的位置計(jì)數(shù)器將產(chǎn)生0x04的內(nèi)存間隙)。

指定“文件”輸出地址:

可以定義如下的memory和section,然后將指定的文件存放于該section,就能控制“文件”的輸出地址。

左右滑動(dòng)查看完整內(nèi)容

/* 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區(qū)域中;更改FLASH的地址或者main_section的LMA,就可以實(shí)現(xiàn)將特定文件指定到特定內(nèi)存區(qū)域。

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

這里描述的RZ/N2L的內(nèi)存分配:

左右滑動(dòng)查看完整內(nèi)容

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

長按可保存查看大圖

把.text段從ATCM改到SYSTEM_RAM:

左右滑動(dòng)查看完整內(nèi)容

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

長按可保存查看大圖

把.data段從ATCM改到SYSTEM_RAM:

左右滑動(dòng)查看完整內(nèi)容

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

長按可保存查看大圖

.bss段的改動(dòng)也是類似的:

左右滑動(dòng)查看完整內(nèi)容

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

長按可保存查看大圖

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5082

    文章

    19126

    瀏覽量

    305299
  • 程序
    +關(guān)注

    關(guān)注

    117

    文章

    3787

    瀏覽量

    81060
  • 腳本
    +關(guān)注

    關(guān)注

    1

    文章

    389

    瀏覽量

    14866

原文標(biāo)題:e2 studio中鏈接腳本的修改指導(dǎo)(通用)

文章出處:【微信號:瑞薩MCU小百科,微信公眾號:瑞薩MCU小百科】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    linux kernel通過修改鏈接腳本lds文件,如何在esp32的linker.lf文件實(shí)現(xiàn)?

    linux kernel通過修改鏈接腳本lds文件實(shí)現(xiàn),請問如何在esp32的linker.lf文件實(shí)現(xiàn)? linux kernel實(shí)現(xiàn)過程:
    發(fā)表于 06-26 06:19

    請問不修改GNU鏈接腳本可以嗎?

    我使用的是Psoc Creator 3.3 SP1的Pro模塊。我不想修改GNU鏈接腳本或使用備用腳本。(更改起始地址和ROM大?。┪覒?yīng)該怎么做,在這個(gè)時(shí)候,這是一個(gè)生成的文件。問候
    發(fā)表于 10-30 06:57

    鏈接腳本的相關(guān)資料下載

    文章目錄鏈接腳本鏈接腳本的特點(diǎn)鏈接腳本的語法鏈接
    發(fā)表于 12-23 08:00

    MDK鏈接腳本的相關(guān)資料分享

    單片機(jī)編程使用 MDK時(shí)不可避免的要涉及到鏈接腳本文件。在鏈接腳本可以指定代碼的存儲布局,可以將代碼段、只讀數(shù)據(jù)段、可讀寫的數(shù)據(jù)段分別存放
    發(fā)表于 12-23 08:19

    RISC-V鏈接腳本的_stack_size的作用是什么

    使用的是CH32V103R8T6的開發(fā)板,代碼是RT-Studio上下載的EVK的例程。對于例程鏈接腳本_stack_size變量的作
    發(fā)表于 11-16 11:28

    蜂鳥e203處理器開源代碼惡的Makefile編譯腳本和測試腳本怎么修改?

    求助蜂鳥e203處理器開源代碼惡的Makefile編譯腳本和測試腳本怎么修改?有沒有大佬指點(diǎn)一下,萬分感謝
    發(fā)表于 08-12 06:52

    在Linux中生成新的gcc工具鏈后,如何使用鏈接腳本來生成能夠被e203使用的.verilog文件?

    求在Linux中生成新的gcc工具鏈后,如何使用鏈接腳本來生成能夠被e203使用的.verilog文件,希望老師能夠提供較為詳細(xì)的步驟指導(dǎo),萬分感謝!
    發(fā)表于 08-12 07:11

    LabVIEW編程指導(dǎo)腳本講解

    LabVIEW編程指導(dǎo)腳本講解,感興趣的可以看看。
    發(fā)表于 06-01 17:28 ?34次下載

    LD鏈接腳本解析-STM32F4xx

    本篇文章主要圍繞項(xiàng)目 STM32_RTOS_GUN 的鏈接腳本 STM32F417IG_FLASH.ld 進(jìn)行分析,同時(shí)對編寫鏈接腳本的方法進(jìn)行相應(yīng)的講解,盡可能地做到通過閱讀這篇文章
    發(fā)表于 11-26 10:51 ?12次下載
    LD<b class='flag-5'>鏈接</b><b class='flag-5'>腳本</b>解析-STM32F4xx

    【gcc編譯優(yōu)化系列】如何獲取gcc默認(rèn)的鏈接腳本

    elf文件這一步,我們需要使用到一個(gè)叫鏈接腳本的文件,這個(gè)文件主要描述了程序的ROM分布和RAM分布,它也直接決定了二進(jìn)制文件的內(nèi)容結(jié)構(gòu)。 那么問題來了,當(dāng)我們手上沒有可用的鏈接
    的頭像 發(fā)表于 07-11 09:15 ?3617次閱讀

    e2 studio創(chuàng)建lib文件及使用

    通過一個(gè)LED閃爍例程,簡單介紹了創(chuàng)建庫文件,使用庫文件的流程。 工具 e 2 studio 復(fù)制以下鏈接到瀏覽器打開獲取瑞薩e 2
    的頭像 發(fā)表于 07-12 12:05 ?1178次閱讀
    <b class='flag-5'>e</b>2 <b class='flag-5'>studio</b>創(chuàng)建lib文件及使用

    關(guān)于STM32CubeIDE鏈接腳本的小問題

    電子發(fā)燒友網(wǎng)站提供《關(guān)于STM32CubeIDE鏈接腳本的小問題.pdf》資料免費(fèi)下載
    發(fā)表于 09-20 11:25 ?0次下載
    關(guān)于STM32CubeIDE<b class='flag-5'>鏈接</b><b class='flag-5'>腳本</b>的小問題

    shell實(shí)例三(編寫批量修改擴(kuò)展名腳本)

    實(shí)現(xiàn)功能: 編寫批量修改擴(kuò)展名腳本,如批量將 txt 文件修改為 doc 文件 執(zhí)行腳本時(shí),需要給腳本添加位置參數(shù)
    的頭像 發(fā)表于 11-09 09:35 ?699次閱讀
    shell實(shí)例三(編寫批量<b class='flag-5'>修改</b>擴(kuò)展名<b class='flag-5'>腳本</b>)

    e2 studiowaveform內(nèi)存渲染工具應(yīng)用

    e2 studiowaveform內(nèi)存渲染工具應(yīng)用
    的頭像 發(fā)表于 09-22 08:07 ?741次閱讀
    <b class='flag-5'>e</b>2 <b class='flag-5'>studio</b><b class='flag-5'>中</b>waveform內(nèi)存渲染工具應(yīng)用

    e2 studio安裝QE的流程介紹

    e2 studio安裝QE的流程介紹
    的頭像 發(fā)表于 04-04 08:05 ?540次閱讀
    在<b class='flag-5'>e</b>2 <b class='flag-5'>studio</b><b class='flag-5'>中</b>安裝QE的流程介紹