Linux中cmd文件的作用是什么

linux中,cmd文件即鏈接命令文件,是存放鏈接器的配置信息的,可簡稱為命令文件;cmd文件的作用是指明如何鏈接程序的。cmd文件由MEMORY和SECTIONS兩部分組成:MEMERY用于定義每個存儲器塊的名字、起始地址和長度;SECTIONS主要用于描述哪個段映射到了哪段存儲空間。

什么是cmd文件?

cmd文件即鏈接命令文件(Linker Command Files),以后綴.cmd結尾。

CMD的專業名稱叫鏈接器配置文件,是存放鏈接器的配置信息的,我們簡稱為命令文件。從其名稱可以看出,該文件的作用是指明如何鏈接程序的。

那么我們知道,在編寫TI DSP程序時,是可以將程序分為很多段,比如text、bss等,各段的作用均不相同。實際在片中運行時,所處的位置也不相同。比如text代碼一般應該放在flash內,而bss的變量應該放在ram內。等等。但是對于不同的芯片,其各存儲器的起止地址都是不一樣的,而且,用戶希望將某一段,尤其是自定義段,放在什么存儲器的什么位置,這也是鏈接器不知道的。為了告訴鏈接器,即將使用的芯片其內部存儲空間的分配和程序各段的具體存放位置,這就需要編寫一個配置文件,即CMD文件了。

cmd文件由MEMORY(即:內存)和SECTIONS(即:段)兩部分組成。MEMERY用于定義每個存儲器塊的名字、起始地址和長度。SECTIONS主要用于描述哪個段映射到了哪段存儲空間。MEMORY中又可分為PAGE0(程序存儲空間)和PAGE1(數據存儲空間),PAGE(即:幀)。

上文所提及的段,又可分為兩大類:已初始化的段和未初始化的段。已初始化的段含有真實的指令和數據,存放于程序存儲空間。未初始化的段只是保留變量的地址空間,未初始化的段并不具有真實的內容,在程序運行過程中才向變量內寫數據進去,存放于數據存儲空間。c語言中,有許多定義好的段,如“.text”,“.const”,“.system”。對于這些定義好的段,在網上有許多關于他們的講解,故這里筆者不再贅述。本文接下來會給讀者介紹作為用戶,來自己定義段的方法。

MEMORY和SECTION

cmd文件中可以寫上注釋,用”/*”和“*/”,包圍起來,但不允許使用“//”,這點與c語言不同。

編寫cmd文件我們需要借助兩條偽指令MEMORY和SECTIONS(必須大寫)。

MEMORY和SECTION的語法可在自行網上查找,本文將結合具體例子對MEMORY和SECTION中的內容進行講解。

結合筆者使用的F28335的cmd文件對MEMORY進行講解。

MEMORY { PAGE?0:????/*?Program?Memory?*/ ???????????/*?Memory?(RAM/FLASH/OTP)?blocks?can?be?moved?to?PAGE1?for?data?allocation?*/ ? ???ZONE0???????:?origin?=?0x004000,?length?=?0x001000?????/*?XINTF?zone?0?*/ ???RAML0???????:?origin?=?0x008000,?length?=?0x001000?????/*?on-chip?RAM?block?L0?*/ ???RAML1???????:?origin?=?0x009000,?length?=?0x001000?????/*?on-chip?RAM?block?L1?*/ ???RAML2???????:?origin?=?0x00A000,?length?=?0x001000?????/*?on-chip?RAM?block?L2?*/ ???RAML3???????:?origin?=?0x00B000,?length?=?0x001000?????/*?on-chip?RAM?block?L3?*/ ???ZONE6???????:?origin?=?0x0100000,?length?=?0x100000????/*?XINTF?zone?6?*/? ???ZONE7A??????:?origin?=?0x0200000,?length?=?0x00FC00????/*?XINTF?zone?7?-?program?space?*/? ???FLASHH??????:?origin?=?0x300000,?length?=?0x008000?????/*?on-chip?FLASH?*/ ???FLASHG??????:?origin?=?0x308000,?length?=?0x008000?????/*?on-chip?FLASH?*/ ???FLASHF??????:?origin?=?0x310000,?length?=?0x008000?????/*?on-chip?FLASH?*/ ???FLASHE??????:?origin?=?0x318000,?length?=?0x008000?????/*?on-chip?FLASH?*/ ???FLASHD??????:?origin?=?0x320000,?length?=?0x008000?????/*?on-chip?FLASH?*/ ???FLASHC??????:?origin?=?0x328000,?length?=?0x008000?????/*?on-chip?FLASH?*/ ???FLASHA??????:?origin?=?0x338000,?length?=?0x007F80?????/*?on-chip?FLASH?*/ ???CSM_RSVD????:?origin?=?0x33FF80,?length?=?0x000076?????/*?Part?of?FLASHA.??Program?with?all?0x0000?when?CSM?is?in?use.?*/ ???BEGIN???????:?origin?=?0x33FFF6,?length?=?0x000002?????/*?Part?of?FLASHA.??Used?for?"boot?to?Flash"?bootloader?mode.?*/ ???CSM_PWL?????:?origin?=?0x33FFF8,?length?=?0x000008?????/*?Part?of?FLASHA.??CSM?password?locations?in?FLASHA?*/ ???OTP?????????:?origin?=?0x380400,?length?=?0x000400?????/*?on-chip?OTP?*/ ???ADC_CAL?????:?origin?=?0x380080,?length?=?0x000009?????/*?ADC_cal?function?in?Reserved?memory?*/ ??? ???IQTABLES????:?origin?=?0x3FE000,?length?=?0x000b50?????/*?IQ?Math?Tables?in?Boot?ROM?*/ ???IQTABLES2???:?origin?=?0x3FEB50,?length?=?0x00008c?????/*?IQ?Math?Tables?in?Boot?ROM?*/?? ???FPUTABLES???:?origin?=?0x3FEBDC,?length?=?0x0006A0?????/*?FPU?Tables?in?Boot?ROM?*/ ???ROM?????????:?origin?=?0x3FF27C,?length?=?0x000D44?????/*?Boot?ROM?*/???????? ???RESET???????:?origin?=?0x3FFFC0,?length?=?0x000002?????/*?part?of?boot?ROM??*/ ???VECTORS?????:?origin?=?0x3FFFC2,?length?=?0x00003E?????/*?part?of?boot?ROM??*/ ? PAGE?1?:???/*?Data?Memory?*/ ???????????/*?Memory?(RAM/FLASH/OTP)?blocks?can?be?moved?to?PAGE0?for?program?allocation?*/ ???????????/*?Registers?remain?on?PAGE1??????????????????????????????????????????????????*/ ??? ???BOOT_RSVD???:?origin?=?0x000000,?length?=?0x000050?????/*?Part?of?M0,?BOOT?rom?will?use?this?for?stack?*/ ???RAMM0???????:?origin?=?0x000050,?length?=?0x0003B0?????/*?on-chip?RAM?block?M0?*/ ???RAMM1???????:?origin?=?0x000400,?length?=?0x000400?????/*?on-chip?RAM?block?M1?*/ ???RAML4???????:?origin?=?0x00C000,?length?=?0x001000?????/*?on-chip?RAM?block?L1?*/ ???RAML5???????:?origin?=?0x00D000,?length?=?0x001000?????/*?on-chip?RAM?block?L1?*/ ???RAML6???????:?origin?=?0x00E000,?length?=?0x001000?????/*?on-chip?RAM?block?L1?*/ ???RAML7???????:?origin?=?0x00F000,?length?=?0x001000?????/*?on-chip?RAM?block?L1?*/ ???ZONE7B??????:?origin?=?0x20FC00,?length?=?0x000400?????/*?XINTF?zone?7?-?data?space?*/ ???FLASHB??????:?origin?=?0x330000,?length?=?0x008000?????/*?on-chip?FLASH?*/ }

可以看到MEMORY中通常包含PAGE0和PAGE1,PAGE0中的RAML0代表起始地址為0x008000,存儲空間長度為0x001000的存儲空間。同理可知其他存儲空間名稱所代表的含義。

對照TI28335芯片數據手冊(僅截取了部分)可以看到,以上cmd文件的編寫是基于TI28335芯片數據手冊內存映射一節所編寫的。我們也可參考芯片數據手冊上的內存映射一節進行cmd文件的編寫。

Linux中cmd文件的作用是什么

接下來,筆者對SECTION所包含的內容進行講解,同樣以F28335的cmd文件為例

SECTIONS { ? ???/*?Allocate?program?areas:?*/ ???.cinit??????????????:?&gt;?FLASHA??????PAGE?=?0 ???.pinit??????????????:?&gt;?FLASHA,?????PAGE?=?0 ???.text???????????????:?&gt;?FLASHA??????PAGE?=?0 ???codestart???????????:?&gt;?BEGIN???????PAGE?=?0 ???ramfuncs????????????:?LOAD?=?FLASHD,? ?????????????????????????RUN?=?RAML0,? ?????????????????????????LOAD_START(_RamfuncsLoadStart), ?????????????????????????LOAD_END(_RamfuncsLoadEnd), ?????????????????????????RUN_START(_RamfuncsRunStart), ?????????????????????????LOAD_SIZE(_RamfuncsLoadSize), ?????????????????????????PAGE?=?0 ? ???csmpasswds??????????:?&gt;?CSM_PWL?????PAGE?=?0 ???csm_rsvd????????????:?&gt;?CSM_RSVD????PAGE?=?0 ??? ???/*?Allocate?uninitalized?data?sections:?*/ ???.stack??????????????:?&gt;?RAMM1???????PAGE?=?1 ???.ebss???????????????:?&gt;?RAML4???????PAGE?=?1 ???.esysmem????????????:?&gt;?RAMM1???????PAGE?=?1 ? ???/*?Initalized?sections?go?in?Flash?*/ ???/*?For?SDFlash?to?program?these,?they?must?be?allocated?to?page?0?*/ ???.econst?????????????:?&gt;?FLASHA??????PAGE?=?0 ???.switch?????????????:?&gt;?FLASHA??????PAGE?=?0?????? ? ???/*?Allocate?IQ?math?areas:?*/ ???IQmath??????????????:?&gt;?FLASHC??????PAGE?=?0??????????????????/*?Math?Code?*/ ???IQmathTables?????:?&gt;?IQTABLES,??PAGE?=?0,?TYPE?=?NOLOAD? ??? ???/*?Uncomment?the?section?below?if?calling?the?IQNexp()?or?IQexp() ??????functions?from?the?IQMath.lib?library?in?order?to?utilize?the? ??????relevant?IQ?Math?table?in?Boot?ROM?(This?saves?space?and?Boot?ROM? ??????is?1?wait-state).?If?this?section?is?not?uncommented,?IQmathTables2 ??????will?be?loaded?into?other?memory?(SARAM,?Flash,?etc.)?and?will?take ??????up?space,?but?0?wait-state?is?possible. ???*/ ???/* ???IQmathTables2????:?&gt;?IQTABLES2,?PAGE?=?0,?TYPE?=?NOLOAD? ???{ ??? ??????????????IQmath.lib<iqnexptable.obj>?(IQmathTablesRam) ??? ???} ???*/ ??? ???FPUmathTables????:?&gt;?FPUTABLES,?PAGE?=?0,?TYPE?=?NOLOAD? ????????? ???/*?Allocate?DMA-accessible?RAM?sections:?*/ ???DMARAML4?????????:?&gt;?RAML4,?????PAGE?=?1 ???DMARAML5?????????:?&gt;?RAML5,?????PAGE?=?1 ???DMARAML6?????????:?&gt;?RAML6,?????PAGE?=?1 ???DMARAML7?????????:?&gt;?RAML7,?????PAGE?=?1 ??? ???/*?Allocate?0x400?of?XINTF?Zone?7?to?storing?data?*/ ???ZONE7DATA????????:?&gt;?ZONE7B,????PAGE?=?1 ? ???/*?.reset?is?a?standard?section?used?by?the?compiler.??It?contains?the?*/? ???/*?the?address?of?the?start?of?_c_int00?for?C?Code.???/* ???/*?When?using?the?boot?ROM?this?section?and?the?CPU?vector?*/ ???/*?table?is?not?needed.??Thus?the?default?type?is?set?here?to??*/ ???/*?DSECT??*/? ???.reset??????????????:?&gt;?RESET,??????PAGE?=?0,?TYPE?=?DSECT ???vectors?????????????:?&gt;?VECTORS?????PAGE?=?0,?TYPE?=?DSECT ??? ???/*?Allocate?ADC_cal?function?(pre-programmed?by?factory?into?TI?reserved?memory)?*/ ???.adc_cal?????:?load?=?ADC_CAL,???PAGE?=?0,?TYPE?=?NOLOAD ? }</iqnexptable.obj>

可以看到SECTION中包含了各種段名。以“.text”為例 ,“.text” 為編譯后生成的二進制指令代碼段,可以看到,我們將“.text”中的內容分配到FLASHA中存儲,而FLASHA位于MEMORY中的PAGE0。

SECTION中的ramfuncs與28335的啟動有關,其本質就是上電運行時通過“引導程序”把用戶代碼從FLASH中讀出,保存在RAM中并在RAM中運行,從而解決ROM讀寫速度慢,難以滿足高速智能芯片和RAM掉電丟失數據的問題。

自定義段

而知道了段的這些信息對于我們用戶來說有什么用呢?最直接的用處就是,當編譯器提示存儲器內存不足時,我們可以通過對應的段名,找到對應的存儲空間,修改其存儲空間的大小來滿足我們程序的需要。甚至我們可以通過自定義段名來存放我們的代碼和數據。

通過#pragma DATA_SECTION(函數名或全局變量名,”用戶自定義在數據空間的段名”)或#pragma CODE_SECTION(函數名或全局變量名,”用戶自定義在程序空間的段名”)可實現自定義段名,從而自由的分配存儲空間。

#pragma DATA_SECTION(用于變量)

#pragma CODE_SECTION(用于函數)

但使用以上指令時需注意:不能在函數體內聲明必須在定義和使用前聲明,#pragma可以阻止對未調用的函數的優化。

下面結合實際使用例子來具體講解:

#pragma?DATA_SECTION(FFT_output,?"FFT_buffer1"); float?FFT_output[FFT_SIZE];

筆者聲明了一個數據段,段名為FFT_buffer1,段的內容在變量FFT_ouput里。而聲明后才定義變量FFT_output的大小。

我們如果想要使用這個自定義的段,接下來我們還要在CMD文件的SECTION中指定FFT_buffer1的存儲空間。

FFT_buffer1		:?&gt;?RAML4,?????PAGE?=?1

通過以上幾條語句,筆者實現了將變量的內容存放入指定的RAML4存儲空間的操作。

從上可以得出,當全局變量所占內存過大時,我們可以通過自定義段選擇有所余裕的存儲空間的方式,從而來解決內存不足的問題。

? 版權聲明
THE END
喜歡就支持一下吧
點贊5 分享