一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

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

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

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

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

454398 ? 來源:alpha007 ? 作者:alpha007 ? 2022-11-25 17:59 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

在前一節(jié)課《源文件(.c/.h/.s)》里,痞子衡給大家系統(tǒng)地介紹了 source 文件,source 文件是嵌入式工程里典型的 input 文件,那么還有沒有其他類型的 input 文件?既然痞子衡這么提問了,那答案肯定是有啦。今天痞子衡要講的 linker 文件就屬于另一種 input 文件。


linker 文件顧名思義就是嵌入式工程在鏈接階段所要用到的文件,source 文件在編譯過程完成之后(此時(shí)已經(jīng)是機(jī)器可識(shí)別的二進(jìn)制機(jī)器碼數(shù)據(jù)),需要再經(jīng)過鏈接器從而將二進(jìn)制數(shù)據(jù)有序組織起來形成最終的二進(jìn)制可執(zhí)行文件,該二進(jìn)制文件最終會(huì)被下載進(jìn)芯片內(nèi)部非易失性存儲(chǔ)器里。linker 文件就是用來指示鏈接器如何組織編譯生成的二進(jìn)制數(shù)據(jù)。


linker 文件是跟 IDE 息息相關(guān)的,本文以 IAR EWARM 為例介紹 linker 文件,其他 IDE 下的 linker 文件可觸類旁通。


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

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


// 常見 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 Systems/Embedded Workbench

xxx/arm/doc/EWARM_DevelopmentGuide.ENU.pdf 文檔里的 Section reference 一節(jié)。


二、解析 linker 文件

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


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


// 動(dòng)詞類關(guān)鍵字


define // 定義各種空間范圍、長(zhǎng)度


initialize // 設(shè)置 section 初始化方法


place in // 放置 section 于某 region 中(具體地址由鏈接器分配)


place at // 放置 section 于某絕對(duì)地址處

// 名詞類關(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 語法的詳細(xì)解釋請(qǐng)查閱 IAR 軟件安裝目錄下 /IAR Systems/Embedded Workbench

xxx/arm/doc/EWARM_DevelopmentGuide.ENU.pdf 文檔里的 The linker configuration file 一節(jié)。


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


此處假設(shè) MCU 物理空間為:ROM(0x0 - 0x1ffff)、RAM(0x10000000 - 0x1000ffff),痞子衡要寫的 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ì)疑問,為何要定義 CodeRelocate、CodeRelocateRam 這兩個(gè) block?按道理說這兩個(gè) block 對(duì)應(yīng)的 section 可以分別放進(jìn) ApplicationFlash 和 ApplicationRam,那為何多此一舉?仔細(xì)上過痞子衡前一節(jié)課 source 文件的朋友肯定就知道答案了,在那節(jié)課里介紹的 startup.c 文件里有一個(gè)叫 init_data_bss()的函數(shù),這個(gè)函數(shù)會(huì)完成初始化 CodeRelocateRam 塊的功能,它找尋的就是 CodeRelocate 段名字,這個(gè)名字比系統(tǒng)默認(rèn)的 textrw 名字看起來更清晰易懂。


2.3 安置 section 集合

第三步便是處理放置那些 section 集合塊了,在放置集合塊之前還有 initialize manually 語句,為什么會(huì)有這些語句?還是得結(jié)合前面提及的 startup.c 文件里的 init_data_bss()函數(shù)來說,這個(gè)函數(shù)是開發(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 段,那么可以用下面語句替換 initialize manually 語句。


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)段,那么有沒有可能在代碼里自定義段呢?想象一下你有這樣的需求,你需要在你的應(yīng)用里開辟一塊 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 };


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


Note:關(guān)于番外內(nèi)容的更多細(xì)節(jié)請(qǐng)查閱 IAR 軟件安裝目錄下 /IAR Systems/Embedded Workbench

xxx/arm/doc/EWARM_DevelopmentGuide.ENU.pdf 文檔里的 Pragma directives 一節(jié)。


至此,嵌入式開發(fā)里的 linker 文件痞子衡便介紹完畢了,掌聲在哪里~~~

審核編輯黃昊宇

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

    關(guān)注

    5145

    文章

    19597

    瀏覽量

    316136
  • Linker
    +關(guān)注

    關(guān)注

    0

    文章

    3

    瀏覽量

    1799
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    嵌入式開發(fā)入門指南:從零開始學(xué)習(xí)嵌入式

    (設(shè)備驅(qū)動(dòng)、內(nèi)核編譯) 4. 推薦的學(xué)習(xí)資源書籍:《嵌入式系統(tǒng)軟件設(shè)計(jì)基礎(chǔ)》《ARM Cortex-M系列嵌入式開發(fā)》在線課程:慕課網(wǎng)、B站嵌入式教學(xué)視頻實(shí)踐平臺(tái):Arduino、STM32開發(fā)
    發(fā)表于 05-15 09:29

    i.MX8MMini中的Cortex-M4不支持SDIO嗎?

    的 FreeRTOS,我們 NXP 論壇獲取了信息,并正在努力為 RTOS 構(gòu)建環(huán)境 我們注意到,在構(gòu)建完成后移植無線驅(qū)動(dòng)程序時(shí)。 RTOS 的當(dāng)前源代碼不包括 SDIO 驅(qū)動(dòng)程序。 i.MX8MMini 中的 Cortex-M4 不支持 SDIO 嗎? 如果支持,您能
    發(fā)表于 04-03 06:45

    瑞薩MCU RA8系列教程:RA8單片機(jī)SysTick使用描述

    ? 每個(gè)Cortex-M內(nèi)核都集成了一個(gè)SysTick模塊,那是因?yàn)檫@個(gè)模塊幾乎是單片機(jī)項(xiàng)目必備的一個(gè)(定時(shí)器)功能。 不管是最新的Cortex-M85內(nèi)核,還是經(jīng)典的Cortex-M3內(nèi)核單片機(jī)
    的頭像 發(fā)表于 03-27 14:27 ?967次閱讀
    瑞薩MCU RA8系列教程:RA8單片機(jī)SysTick使用描述

    瑞薩RA8快速上手指南:Cortex-M85內(nèi)核瑞薩RA8開發(fā)環(huán)境搭建 并點(diǎn)亮一個(gè)LED

    因?yàn)?b class='flag-5'>Cortex-M內(nèi)核,瑞薩RA8系列單片機(jī)支持多種市面上常見的開發(fā)環(huán)境,像Keil MDK、IAR EWARM等,而本文講述的是瑞薩自家官方的IDE(e2 studio)。
    的頭像 發(fā)表于 03-17 14:35 ?922次閱讀
    瑞薩RA8快速上手指南:<b class='flag-5'>Cortex-M</b>85內(nèi)核瑞薩RA8<b class='flag-5'>開發(fā)</b>環(huán)境搭建 并點(diǎn)亮一個(gè)LED

    【瑞薩RA2L1入門學(xué)習(xí)】00. 開箱 + 點(diǎn)燈

    【開箱】 開發(fā)板外觀展示 主控介紹 RA-Eco-RA2L1-48PIN-V1.0開發(fā)板使用主控芯片為 R7FA2L1AB2DFL。 基于48 MHz Arm? Cortex?-M
    發(fā)表于 03-07 11:07

    Arm Cortex-A320 CPU助力嵌入式設(shè)備實(shí)現(xiàn)高能效AI計(jì)算

    ,要確定適合特定 AI 應(yīng)用的處理器,系統(tǒng)開發(fā)者需要通過比較基于 Arm Cortex-A、Arm Cortex-M 和 Arm Ethos-U NPU 的設(shè)備及其可能的搭配進(jìn)行決策。除了成本的考量,
    的頭像 發(fā)表于 02-27 17:17 ?715次閱讀
    Arm <b class='flag-5'>Cortex</b>-A320 CPU助力嵌入式設(shè)備實(shí)現(xiàn)高能效AI計(jì)算

    Cortex-M3/M4F指令集技術(shù)用戶手冊(cè)

    電子發(fā)燒友網(wǎng)站提供《Cortex-M3/M4F指令集技術(shù)用戶手冊(cè).pdf》資料免費(fèi)下載
    發(fā)表于 12-23 16:31 ?8次下載
    <b class='flag-5'>Cortex-M</b>3/<b class='flag-5'>M</b>4F指令集技術(shù)用戶手冊(cè)

    如何使用Ozone分析Cortex-M異常

    Ozone可以幫助用戶快速分析和查找導(dǎo)致CPU故障的軟件bug。本文解釋如何使用Ozone的調(diào)試功能,深入了解Cortex-M架構(gòu)上的這些錯(cuò)誤。
    的頭像 發(fā)表于 11-29 11:14 ?1600次閱讀
    如何使用Ozone分析<b class='flag-5'>Cortex-M</b>異常

    新唐科技率先發(fā)布免費(fèi)版Arm Keil MDK,助力嵌入式開發(fā)

    基于Arm Cortex?-M系列的新唐微控制器設(shè)計(jì),全面覆蓋Cortex-M0/M0+/M2
    的頭像 發(fā)表于 11-06 11:07 ?2297次閱讀

    ARM開發(fā)板與樹莓派的比較

    處理器 ARM開發(fā)板通常采用不同的ARM處理器,如Cortex-A系列、Cortex-M系列等,而樹莓派則主要使用博通的ARM處理器。樹莓派的處理器性能相對(duì)較高,尤其是在最新的樹莓派4B上,搭載了四核
    的頭像 發(fā)表于 11-05 11:11 ?1332次閱讀

    【RA-Eco-RA2E1-48PIN-V1.0開發(fā)板試用】RA-Eco-RA2E1-48PIN-V1.0開發(fā)板基于Keil MDK環(huán)境搭建

    與 RA2L1 產(chǎn)品群引腳和外圍設(shè)備兼容,特別適用于電池供電應(yīng)用以及空間受限應(yīng)用,以及其他需要高性能和低功耗的系統(tǒng)。 RA2L1 基于 ARM? Cortex?-M23 核心(現(xiàn)今 Arm? Cortex-M
    發(fā)表于 11-04 22:58

    實(shí)際項(xiàng)目開發(fā)中為何選擇ARM? Cortex?-M4 內(nèi)核的HK32MCU?

    ?Cortex?-M4內(nèi)核的HK32F407芯片的深度知識(shí),并圍繞各類實(shí)際案例詳細(xì)解讀了如何選型,為何選擇ARM?Cortex?-M4內(nèi)核的HK32MCU。航順芯片深耕32
    的頭像 發(fā)表于 10-22 17:19 ?806次閱讀
    實(shí)際項(xiàng)目<b class='flag-5'>開發(fā)</b>中為何選擇ARM? <b class='flag-5'>Cortex</b>?-<b class='flag-5'>M</b>4 內(nèi)核的HK32MCU?

    基于瑞薩Arm Cortex-M85 MCU Feather SOM的解決方案

    開源社區(qū)已經(jīng)傳統(tǒng)的黑客聚集地逐漸擴(kuò)展到家庭、辦公室以及工業(yè)應(yīng)用等廣泛領(lǐng)域。在這個(gè)過程中,瑞薩的Arm Cortex-M85 MCU Feather SOM憑借著卓越的性能和豐富的功能,為開源硬件愛好者和專業(yè)開發(fā)者提供了強(qiáng)大的支
    的頭像 發(fā)表于 08-19 17:32 ?826次閱讀

    樹莓派Pico 2發(fā)布,搭載RP2350雙核RISC-V和Arm Cortex-M33微控制器!

    復(fù)雜得多的設(shè)計(jì),具有: – 兩個(gè) 150MHz Arm Cortex-M33 內(nèi)核,支持浮點(diǎn)和 DSP – 內(nèi)置 520KB SRAM – 圍繞 Arm TrustZone for Cortex-M
    發(fā)表于 08-13 10:07

    米爾基于NXP iMX.93開發(fā)板的M33處理器應(yīng)用開發(fā)筆記

    1.概述本文主要介紹M33核的兩種工程調(diào)試開發(fā),第一種方式是通過板子自帶的固件進(jìn)行開發(fā),第種方式是使用IAREmbeddedWorkbench來構(gòu)建可移植的Freertos
    的頭像 發(fā)表于 06-29 08:01 ?2086次閱讀
    米爾基于NXP iMX.93<b class='flag-5'>開發(fā)</b>板的<b class='flag-5'>M</b>33處理器應(yīng)用<b class='flag-5'>開發(fā)</b>筆記