ARM Cortex-M底層技術(七)KEIL MDK 分散加載-1-分散加載的結構

 

 

KEIL MDK 分散加載的結構

    

1、我們先來解剖一隻麻雀    

    很多人會說我做項目時沒用過分散加載啊,可能有些人甚至都不知道它的存在。事實上,開發環境會默認生成一個分散加載文件(或者叫鏈接器描述文件),你使用的可能就是這個默認的分散加載文件,先來看一下Keil默認生成的分散加載文件,使用LPC54608隨便找了一個示例代碼用Keil生成了一個,如下圖所示:

    

    這個分散加載是keil自己生成的分散加載,可以說是最簡單的分散加載,簡單到RO、RW、ZI基本都是隨意擺放的;裏面紅色字體的是各個段的起始地址以及大小,這些段的起始地址以及大小是由下圖的紅框框定的部分決定的,你可以把上圖以及下面這張圖合起來看,地址是一致的。

    

    這個分散加載文件的基本意思如下圖:

    

    這裏面Flash以及SRAM的地址以及大小都是可以修改的,其他的也可以修改,但起始地址以及大小都要在芯片真實存在的有效物理地址上,這部分需要參看芯片的用戶手冊裏面的Memory MAP一節的內容,如下圖就是LPC54608的Memory MAP,參看分散加載裏面的地址,Flash以及SRAM的起始地址以及大小都落在有效的空間上了。如果你定義的Flash起始地址在0x40000000,那麼肯定會出錯,因爲與AHB總線地址衝突了。

 

 

           

2、分散加載的基本結構

 

    我們舉個例子來說明分散加載文件的基本機構,如下:

 

LOAD_ROM_1 0x0000              【加載域描述】這段是要告訴鏈接器,你的程序是存在哪裏?我從哪裏去找需要執行的代碼。
{                                                                        
    EXEC_ROM_1 0x0000           【運行域描述】這段是要告訴鏈接器,你的程序在哪裏執行,在ARM Cortex-M系列的絕大多
    {                                                                    數MCU中加載域以及運行域是在同一個空間上的,即片內Flash。
        program1.o (+RO)            【輸入節描述】就是告訴鏈接器,具體把哪一個以及怎麼把這一個obj文件放到運行域裏面
    }
    DRAM 0x18000 0x8000        【運行域描述】這裏指的是RAM空間的運行域,下面會解釋爲什麼這裏會有兩個運行域
    {
        program1.o (+RW,+ZI)     【輸入節描述】告訴鏈接器,去哪裏找執行程序是需要使用的變量以及數據
    }
}

 

LOAD_ROM_2 0x4000                【另一個加載域描述】同一個工程可以有多個加載域,就好像同一臺電腦可以裝幾個操作系統
{
    EXEC_ROM_2 0x4000             【另一個運行域描述】
    {
        program2.o (+RO)             【另一個輸入節
    }
    SRAM 0x8000 0x8000            【另一個運行域描述】
    {
        program2.o (+RW,+ZI)      【另一個輸入節
    }
}

    其實Keil的官方幫助文檔裏面有官方的對分散加載的全面介紹與使用指導,但是裏面的東西語言太官方了,搞了一大堆定義,然後又例子又很少,一大堆的專業術語,小編我最開始學這部分內容就是啃的這部分,真是想死的心情停不了啊~。好吧,下面我儘量多舉例子,儘量少扯那些亂七八糟的術語,下面我們開始:

    你可能會問,這個分散加載文件是用什麼語言編寫的?是一種腳本語言,不是C語言也不是彙編,所以分散加載不能調試,它是一種叫做BNF的東東,官方文檔裏面把這東西描述的極其神祕,反正我是沒太看懂這個所謂的BNF到底是個啥東東(據說是一個符號推導語言之類的一般存在於各種專業論文裏面用於裝B的東西),但是經過多個工程的磨練,小編我也基本弄明白了這東西該怎麼用了,至於理論層面我沒有深究,這個東東貌似做分散加載的描述腳本有些大材小用了,它能做的事情遠不止於此,當然其他的跟我們沒關係啦。

    對於上面這個例子的幾點說明:

    <1>分散加載的根本功能是指定程序在存儲空間上面的存儲分配以及運行空間的分配~,所有要有加載域和運行域來分別指定程序存儲空間以及程序運行空間。一般來說程序的運行空間是在芯片的ROM類存儲器裏面,在Cortex-M裏面基本就是芯片內部的Flash空間;

    <2>運行域就有意思了,由於MCU內部的Flash(幾乎都是Nor-Flash)是可以運行代碼的,但是不能用於變量也就是RW與ZI的加載,主要原因是變量需要經常修改,幾個小時就可能連續改變幾十萬次,但是目前Flash工藝的寫壽命介於10萬次~100萬次之間,如果把RW和ZI放在Flash上,那就是災難,Flash會因爲寫次數的限制很快就會掛掉,而且Flash只能按塊操作,開銷太大,所以一般都是放到SRAM裏面,所以你會看到在這個例子裏面,運行域分成兩個部分,RO數據段放在內部Flash裏面,RW與ZI放到片內SRAM中去執行。這點與電腦是不同的,電腦的硬盤是完全不能執行程序的,所以如果你把電腦看成MCU的話,用Keil來編寫程序的話,那麼電腦的RO、RW、ZI段都是放到內存上執行的,也就是說電腦實際上只有一個執行域就在內存上,可以類似理解爲MCU的片內SRAM上。其實很多市面上的A7、A8、A9、A53等內核的應用處理器運行Linux與Android也可以類比爲電腦,所有的東西都要加載到RAM上運行。

    <3>所以分散加載可以簡單理解爲的最基本結構就是至少3個域(這個事實上不對,但是對於大多數Cortex-M系列MCU的分散加載可以這樣簡單理解):至少一個加載域、建議兩個運行域(一個RO運行域、一個RW+ZI運行域),就是你要告訴鏈接器至少3個信息,即:從哪裏加載程序(至少一個域)、在哪裏運行程序(至少一個域)、在哪裏讀寫程序運行中用到的變量(至少一個域,實際上也可以跟運行程序的域在一起,但強烈建議分開)。如果你自己編寫分散加載文件,先把這把這3個結構寫出來,我們再來看之前的麻雀:            

    

    LR_IROM1就是【加載域】,指定了用戶程序存儲在0x00000000起始大小爲0x80000的地址上,用戶程序從這個區域內加載;

    ER_IROM1就是【運行域】,是RO的運行域,因爲LPC54608內部的Flash可以運行代碼,所以用戶代碼可以從這個區域內運行;

    RW_IRAM1就是【運行域】,是RW+ZI的運行域,這裏指向的是片內SRAM的地址。

    這樣一解構,整個分散加載的基本結構就比較清晰了,下面我們再來看一個複雜一點的,同樣的LPC54608的工程的分散加載                

    這個大家仔細看下這個結構,基本上上面所說的3個域結構的擴展。這裏有幾點不同的獨特地方,我們解釋下:

    1、USB單獨搞了兩個運行域出來是幹嘛的?

        是這樣的,USB由於要大量的數據吞吐,單獨開闢一塊SRAM作爲數據BUFFER,所以你看到加載域2和加載域3的地址是在片內SRAM上,你可以對照一下上面的LPC5460的Memory MAP就會發現這兩塊地址是在片內SRAM上的。

    2、分散加載還可以指定堆棧????

        沒錯,確實可以,上面這個例子就在分散加載裏面指定了堆棧其中:

        ARM_LIB_HEAP域ARM_LIB_STACK是兩個編譯器之前就定義好的標號(Symbol),用於處理堆棧分配。當然堆棧也可以在啓動代碼裏面指定分配,這是兩種不同的方式,上面這個例子是在分散加載中指定堆棧。

        關於分散加載,我們要講的遠不止於此,接下來,我們還會用幾篇文檔的篇幅來深入探討這部分的技術。

原文鏈接:https://blog.csdn.net/weixin_39118482/article/details/79895378

發佈了17 篇原創文章 · 獲贊 16 · 訪問量 2465
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章