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

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

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

從文件角度看Cortex-M開(kāi)發(fā)—鏈接文件

冬至子 ? 來(lái)源:痞子衡嵌入式 ? 作者:痞子衡 ? 2023-12-13 15:17 ? 次閱讀

一、 嵌入式系統(tǒng)中的section

在講linker文件之前,痞子衡必須先跟大家理清一個(gè)嵌入式系統(tǒng)中很重要的概念-section。那么什么是section?我們寫(xiě)的C或者匯編source文件里都是各種應(yīng)用代碼,這些代碼按功能可以分為很多種類(lèi),比如常量、變量、函數(shù)、堆棧等,而相同類(lèi)型的代碼的集合便是一個(gè)section,鏈接器在鏈接時(shí)組織數(shù)據(jù)的基本單元便是section。那么一個(gè)典型的嵌入式系統(tǒng)中到底有多少種section呢?下面列出了IAR里默認(rèn)的所有section,那些常見(jiàn)section在后續(xù)介紹linker文件里會(huì)被提到。

//常見(jiàn)Section
.bss                 // Holds zero-initialized static and global variables.
CSTACK               // Holds the stack used by C or C++ programs.
.data                // Holds static and global initialized variables.
.data_init           // Holds initial values for .data sections when the linker directive initialize is used.
HEAP                 // Holds the heap used for dynamically allocated data.
.intvec              // Holds the reset vector table
.noinit              // Holds __no_init static and global variables.
.rodata              // Holds constant data.
.text                // Holds the program code.
.textrw              // Holds __ramfunc declared program code.
.textrw_init         // Holds initializers for the .textrw declared section.

//較冷僻Section
.exc.text            // Holds exception-related code.
__iar_tls.$$DATA     // Holds initial values for TLS variables.
.iar.dynexit         // Holds the atexit table.
.init_array          // Holds a table of dynamic initialization functions.
IRQ_STACK            // Holds the stack for interrupt requests, IRQ, and exceptions.
.preinit_array       // Holds a table of dynamic initialization functions.
.prepreinit_array    // Holds a table of dynamic initialization functions.
Veneer$$CMSE         // Holds secure gateway veneers.

//更冷僻Section
.debug               // Contains debug information in the DWARF format
.iar.debug           // Contains supplemental debug information in an IAR format
.comment             // Contains the tools and command lines used for building the file
.rel or .rela        // Contains ELF relocation information
.symtab              // Contains the symbol table for a file
.strtab              // Contains the names of the symbol in the symbol table
.shstrtab            // Contains the names of the sections.

Note:上述section的詳細(xì)解釋請(qǐng)查閱IAR軟件安裝目錄下IAR SystemsEmbedded Workbench xxxarmdocEWARM_DevelopmentGuide.ENU.pdf文檔里的Section reference一節(jié)。

二、解析linker文件

知道了section概念,那便可開(kāi)始深入了解linker文件,什么是linker文件?linker文件是按IDE規(guī)定的語(yǔ)法寫(xiě)成的用于指示鏈接器分配各section在嵌入式系統(tǒng)存儲(chǔ)器中存放位置的文件。大家都知道嵌入式系統(tǒng)存儲(chǔ)器主要分為兩類(lèi):ROM(非易失性),RAM(易失性),所以相應(yīng)的這些section根據(jù)存放的存儲(chǔ)器位置不同也分為兩類(lèi)屬性:readonly, readwrite。實(shí)際上linker文件的工作就是將readonly section放進(jìn)ROM,readwrite section放進(jìn)RAM。

那么到底該如何編寫(xiě)工程的linker文件呢?正如前面所言,linker文件也是有語(yǔ)法的,而且這語(yǔ)法是由IDE指定的,所以必須要先掌握IDE制定的語(yǔ)法規(guī)則,linker文件語(yǔ)法規(guī)則相對(duì)簡(jiǎn)單,最常用的關(guān)鍵字就是如下8個(gè):

// 動(dòng)詞類(lèi)關(guān)鍵字
define                // 定義各種空間范圍、長(zhǎng)度
initialize            // 設(shè)置section初始化方法
place in              // 放置section于某region中(具體地址由鏈接器分配)
place at              // 放置section于某絕對(duì)地址處

// 名詞類(lèi)關(guān)鍵字
symbol                // 各種空間范圍、長(zhǎng)度的標(biāo)識(shí)
memory                // 整個(gè)ARM內(nèi)存空間的標(biāo)識(shí)
region                // 在整個(gè)ARM內(nèi)存空間中劃分某region空間的標(biāo)識(shí)
block                 // 多個(gè)section的集合塊的標(biāo)識(shí)

Note:上述linker語(yǔ)法的詳細(xì)解釋請(qǐng)查閱IAR軟件安裝目錄下IAR SystemsEmbedded Workbench xxxarmdocEWARM_DevelopmentGuide.ENU.pdf文檔里的The linker configuration file一節(jié)。

到這里我們已經(jīng)可以開(kāi)始愉快地寫(xiě)linker文件了,是不是有點(diǎn)按捺不住了?來(lái)吧,只需要三步走,Let's do it。

此處假設(shè)MCU物理空間為:ROM(0x0 - 0x1ffff)、RAM(0x10000000 - 0x1000ffff),痞子衡要寫(xiě)的linker要求如下:

  • 中斷向量表必須放置于ROM起始地址0x0,且必須256字節(jié)對(duì)齊
  • STACK大小為8KB,HEAP大小為1KB,且必須8字節(jié)對(duì)齊
  • SATCK必須放置在RAM起始地址0x10000000
  • 其余section放置在正確的region里,具體空間由鏈接器自動(dòng)分配

2.1 定義物理空間

第一步我們先定義3塊互不重疊的空間ROM_region、RAM_region、STACK_region,其中ROM_region對(duì)應(yīng)的是真實(shí)的ROM空間,RAM_region和STACK_region組合成真實(shí)的RAM空間。

// 定義物理空間邊界
define symbol __ICFEDIT_region_ROM_start__ = 0x00000000;
define symbol __ICFEDIT_region_ROM_end__   = __ICFEDIT_region_ROM_start__ + (128*1024 - 1);
define symbol __ICFEDIT_region_RAM_start__ = 0x10000000;
define symbol __ICFEDIT_region_RAM_end__   = __ICFEDIT_region_RAM_start__ + (64*1024 - 1);
define symbol __ICFEDIT_intvec_start__     = __ICFEDIT_region_ROM_start__;

// 定義堆棧長(zhǎng)度
define symbol __ICFEDIT_size_cstack__      = (8*1024);
define symbol __ICFEDIT_size_heap__        = (1*1024);

// 定義各region具體空間范圍
define memory mem with size = 4G;
define region ROM_region    = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
define region STACK_region  = mem:[from __ICFEDIT_region_RAM_start__ to  __ICFEDIT_region_RAM_start__ + __ICFEDIT_size_cstack__ - 1];
define region RAM_region    = mem:[from __ICFEDIT_region_RAM_start__ + __ICFEDIT_size_cstack__  to __ICFEDIT_region_RAM_end__];

2.2 定義section集合

第二步是自定義section集合塊,細(xì)心的朋友可以看到右邊花括號(hào)里包含的都是上一節(jié)介紹的系統(tǒng)默認(rèn)section,我們會(huì)把具有相同屬性的section集合成到一個(gè)block里,方便下一步的放置工作。

// 定義堆棧塊及其屬性
define block CSTACK    with alignment = 8, size = __ICFEDIT_size_cstack__   { };
define block HEAP      with alignment = 8, size = __ICFEDIT_size_heap__     { };

// 定義section集合塊
define block Vectors with alignment=256 { readonly section .intvec };
define block CodeRelocate               { section .textrw_init };
define block CodeRelocateRam            { section .textrw };
define block ApplicationFlash           { readonly, block CodeRelocate };
define block ApplicationRam             { readwrite, block CodeRelocateRam, block HEAP };

有朋友可能會(huì)疑問(wèn),為何要定義CodeRelocate、CodeRelocateRam這兩個(gè)block?按道理說(shuō)這兩個(gè)block對(duì)應(yīng)的section可以分別放進(jìn)ApplicationFlash和ApplicationRam,那為何多此一舉?仔細(xì)上過(guò)痞子衡前一節(jié)課source文件的朋友肯定就知道答案了,在那節(jié)課里介紹的startup.c文件里有一個(gè)叫init_data_bss()的函數(shù),這個(gè)函數(shù)會(huì)完成初始化CodeRelocateRam塊的功能,它找尋的就是CodeRelocate段名字,這個(gè)名字比系統(tǒng)默認(rèn)的textrw名字看起來(lái)更清晰易懂。

2.3 安置section集合

第三步便是處理放置那些section集合塊了,在放置集合塊之前還有initialize manually語(yǔ)句,為什么會(huì)有這些語(yǔ)句?還是得結(jié)合前面提及的startup.c文件里的init_data_bss()函數(shù)來(lái)說(shuō),這個(gè)函數(shù)是開(kāi)發(fā)者自己實(shí)現(xiàn)的data,bss段的初始化,所以此處需要通知IDE,你不需要再幫我做初始化工作了。

// 設(shè)置初始化方法
initialize manually { readwrite };
initialize manually { section .data};
initialize manually { section .textrw };
do not initialize   { section .noinit };

// 放置section集合塊
place at start of ROM_region { block Vectors };
//place at address mem:__ICFEDIT_intvec_start__ { block Vectors };
place in ROM_region          { block ApplicationFlash };
place in RAM_region          { block ApplicationRam };
place in STACK_region        { block CSTACK };

當(dāng)然如果你希望IDE幫你自動(dòng)初始化data,bss,textrw段,那么可以用下面語(yǔ)句替換initialize manually語(yǔ)句。

initialize by copy { readwrite, section .textrw };

設(shè)置好初始化方法后,便是放置section集合塊了,放置方法主要有兩種,place in和place at,前者用于指定空間塊放置(不指定具體地址),后者是指定具體地址放置。

至此一個(gè)基本的linker文件便大功告成了,是不是so easy?

番外一、自定義section

有耐心看到這里的朋友,痞子衡必須得放個(gè)大招獎(jiǎng)勵(lì)一下,前面講的都是怎么處理系統(tǒng)默認(rèn)段,那么有沒(méi)有可能在代碼里自定義段呢?想象一下你有這樣的需求,你需要在你的應(yīng)用里開(kāi)辟一塊1KB的可更新的數(shù)據(jù)區(qū),你想把這個(gè)數(shù)據(jù)區(qū)指定到地址0x18000 - 0x183ff的范圍內(nèi),你需要在應(yīng)用里定義4 Byte的只讀config block常量指向這個(gè)可更新數(shù)據(jù)區(qū)首地址(這段config block只會(huì)被外部debugger或者bootloader更新),如何做到?

// C文件中
/////////////////////////////////////////////////////
// 用@操作符指定變量myConfigBlock[4]放進(jìn)自定義.myBuffer section
const uint8_t myConfigBlock[4] @ ".myBuffer" = {0x00, 0x01, 0x02, 0x03};

// Linker文件中
/////////////////////////////////////////////////////
// 自定義指定的mySection_region,并把.myBuffer放到這個(gè)region
define region mySection_region = mem:[from  0x0x18000 to 0x183ff];
place at start of mySection_region { readonly section .myBuffer };

上面做到了將代碼中的常量放入自定義段?,那么怎么將代碼中的函數(shù)也放進(jìn)自定義段呢?繼續(xù)看下去

// C文件中
/////////////////////////////////////////////////////
// 用#pragma location指定函數(shù)myFunction()放進(jìn)自定義.myTask section
#pragma location = ".myTask"
void myFunction(void)
{
    __NOP();
}

// Linker文件中
/////////////////////////////////////////////////////
// 把.myTask放到mySection_region
place in mySection_region { readonly section .myTask };

看起來(lái)大功告成了,最后還有一個(gè)注意事項(xiàng),如果myConfigBlock在代碼中并未被引用,IDE在鏈接的時(shí)候可能會(huì)忽略這個(gè)變量(IDE認(rèn)為它沒(méi)用,所以優(yōu)化了),那么怎么讓IDE強(qiáng)制鏈接myConfigBlock呢?IAR留了個(gè)后門(mén),在options->Linker->Input選項(xiàng)卡中的Keep symbols輸入框里填入你想強(qiáng)制鏈接的對(duì)象名(注意是代碼中的對(duì)象名,而非linker文件中的自定義段名)即可。

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

    關(guān)注

    38

    文章

    7405

    瀏覽量

    163407
  • 嵌入式系統(tǒng)
    +關(guān)注

    關(guān)注

    41

    文章

    3532

    瀏覽量

    128989
  • RAM
    RAM
    +關(guān)注

    關(guān)注

    8

    文章

    1352

    瀏覽量

    114376
  • IAR
    IAR
    +關(guān)注

    關(guān)注

    5

    文章

    344

    瀏覽量

    36563
  • Cortex-M
    +關(guān)注

    關(guān)注

    2

    文章

    227

    瀏覽量

    29690
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    為什么說(shuō)Cortex-M是低功耗應(yīng)用的首選

    雖然Cortex-M處理器家族目標(biāo)瞄準(zhǔn)效能光譜較低端的區(qū)域,但是和大多數(shù)微控制器(MCU)采用的其他典型處理器相比,Cortex-M的效能依然算相當(dāng)強(qiáng)悍。舉例來(lái)說(shuō),像是許多高效能微控制器所采用的Cortex-M4與
    發(fā)表于 07-28 09:44 ?3441次閱讀
    為什么說(shuō)<b class='flag-5'>Cortex-M</b>是低功耗應(yīng)用的首選

    基于Cortex-M處理器做產(chǎn)品開(kāi)發(fā)為什么受歡迎

    基于Cortex-M處理器做產(chǎn)品開(kāi)發(fā)為什么受歡迎雖然Cortex-M系列處理器有非常多的特性,但是很容易使用,差不多所有的開(kāi)發(fā)都可以用像C語(yǔ)言這樣的高級(jí)編程語(yǔ)言。雖然基于
    發(fā)表于 08-27 16:11

    Cortex-M入門(mén)資料和書(shū)籍分享

    Cortex-M入門(mén)在網(wǎng)上博客逛論壇也是能學(xué)到些東西的,但通常是知識(shí)點(diǎn),不能構(gòu)成知識(shí)面。書(shū)籍通常會(huì)系統(tǒng)性地講述,通過(guò)書(shū)籍可以建立起知識(shí)面,只有建立起了知識(shí)面才算是掌握。推薦兩本書(shū):《ARM
    發(fā)表于 07-01 09:38

    ARM Cortex-M內(nèi)核的相關(guān)資料推薦

    8代產(chǎn)品,除了上一篇 《Cortex-M功能模塊差異》 介紹過(guò)的CM0/CM0+、CM1、CM3、CM4、CM7,還有主打安全特性的CM23、CM33、CM35P。1.Cortex-M...
    發(fā)表于 12-27 07:21

    ARM Cortex-M 開(kāi)發(fā)實(shí)戰(zhàn)指南入門(mén)篇(二)

    1、集成開(kāi)發(fā)環(huán)境和非集成開(kāi)發(fā)環(huán)境介紹嵌入式開(kāi)發(fā)的第一步就是搭建開(kāi)發(fā)環(huán)境,不同的硬件平臺(tái)可能所需的環(huán)境還不太一樣,而且還有可能出現(xiàn)千奇百怪的錯(cuò)誤,本講將講解ARM
    發(fā)表于 04-19 17:24

    介紹Cortex-A和Cortex-M的TrustZone之間的差異

    相信關(guān)注安全和嵌入式的開(kāi)發(fā)者對(duì)TrustZone都不陌生,最近看到有網(wǎng)友在問(wèn)Cortex-A和Cortex-M的TrustZone之間的差異,我們來(lái)簡(jiǎn)單介紹下。Arm在2003年的Armv6開(kāi)始
    發(fā)表于 07-13 14:45

    5V供電Cortex-M微控制器

    Cortex-M架構(gòu)的微控制器是3.3V供電的,最近幾年才出現(xiàn)一些5V供電的Cortex-M微控制器,這里列出了部分5V供電的Cortex-M微控制器系列,點(diǎn)擊鏈接打開(kāi)官網(wǎng)。 ming
    發(fā)表于 11-25 02:22 ?720次閱讀

    關(guān)于Cortex-M 調(diào)試應(yīng)用的介紹

    Cortex-M 調(diào)試應(yīng)用
    的頭像 發(fā)表于 07-10 00:56 ?2559次閱讀

    米爾科技Cortex-M Prototyping System +介紹

    經(jīng)濟(jì)實(shí)惠的主板,作為ARM?Versatile?Express系列開(kāi)發(fā)板的一部分。他們提供兩種FPGA的選擇,用于原型設(shè)計(jì)基于Cortex-M的設(shè)計(jì)和一系列不同的調(diào)試選項(xiàng)。它提供了一系列實(shí)用的外設(shè),包括
    的頭像 發(fā)表于 11-14 10:45 ?1791次閱讀
    米爾科技<b class='flag-5'>Cortex-M</b> Prototyping System +介紹

    Cortex-MCortex-A認(rèn)識(shí)ARM處理器

    Cortex-MCortex-A認(rèn)識(shí)ARM處理器
    的頭像 發(fā)表于 03-08 11:34 ?3369次閱讀

    文件角度,了解Cortex-M開(kāi)發(fā)(二)

    衡這么提問(wèn)了,那答案肯定是有啦。今天痞子衡要講的 linker 文件就屬于另一種 input 文件。 linker 文件顧名思義就是嵌入式工程在鏈接階段所要用到的
    的頭像 發(fā)表于 11-25 17:59 ?429次閱讀

    文件角度了解Cortex-M開(kāi)發(fā)(1)

    。 盡管在平常開(kāi)發(fā)中,我們都只會(huì)關(guān)注自己創(chuàng)建的 .c/.h/.s 源文件,但實(shí)際上我們不知不覺(jué)中也跟很多不是我們創(chuàng)建的源文件在打交道,那么問(wèn)題來(lái)了,一個(gè)完整的嵌入式工程(以基于 ARM Cor
    的頭像 發(fā)表于 10-30 10:44 ?500次閱讀

    Could not stop Cortex-M device!Please check the JTAG cable.

    Cortex-M device!Please check the JTAG cable.”問(wèn)題首先彈出然后彈出這個(gè)。網(wǎng)上查找原因,嘗試了n多種提到的解決辦法都失敗了!于是懷疑是不是文件哪里被更改...
    發(fā)表于 12-01 11:36 ?27次下載
    Could not stop <b class='flag-5'>Cortex-M</b> device!Please check the JTAG cable.

    Cortex-M3精通之路-1(匯編啟動(dòng)文件)

    對(duì)讀者的要求是較高的,建議細(xì)細(xì)閱讀。 精通ARM Cortex-M意味著對(duì)ARM Cortex-M內(nèi)核及相關(guān)微控制器有深入全面的理解和高超的開(kāi)發(fā)技能。具體需要: 1. 深入理解ARM
    的頭像 發(fā)表于 05-28 11:32 ?1441次閱讀
    <b class='flag-5'>Cortex-M</b>3精通之路-1(匯編啟動(dòng)<b class='flag-5'>文件</b>)

    Cortex-M位帶操作的原理

    Cortex-M位帶操作的原理
    的頭像 發(fā)表于 10-24 15:27 ?797次閱讀
    <b class='flag-5'>Cortex-M</b>位帶操作的原理