在Linux中,cmd檔案即連結指令文件,是存放連結器的設定資訊的,可簡稱為指令檔;cmd檔案的作用是指明如何連結程式的。 cmd檔案由MEMORY和SECTIONS兩部分組成:MEMERY用於定義每個記憶體區塊的名字、起始位址和長度;SECTIONS主要用於描述哪個段映射到了哪段儲存空間。
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”。對於這些定義好的段落,在網路上有許多關於他們的講解,故這裡筆者不再贅述。本文接下來會給讀者介紹作為用戶,來自己定義段的方法。
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檔案的編寫。
接下來,筆者對SECTION所包含的內容進行講解,同樣以F28335的cmd檔為例
SECTIONS { /* Allocate program areas: */ .cinit : > FLASHA PAGE = 0 .pinit : > FLASHA, PAGE = 0 .text : > FLASHA PAGE = 0 codestart : > BEGIN PAGE = 0 ramfuncs : LOAD = FLASHD, RUN = RAML0, LOAD_START(_RamfuncsLoadStart), LOAD_END(_RamfuncsLoadEnd), RUN_START(_RamfuncsRunStart), LOAD_SIZE(_RamfuncsLoadSize), PAGE = 0 csmpasswds : > CSM_PWL PAGE = 0 csm_rsvd : > CSM_RSVD PAGE = 0 /* Allocate uninitalized data sections: */ .stack : > RAMM1 PAGE = 1 .ebss : > RAML4 PAGE = 1 .esysmem : > RAMM1 PAGE = 1 /* Initalized sections go in Flash */ /* For SDFlash to program these, they must be allocated to page 0 */ .econst : > FLASHA PAGE = 0 .switch : > FLASHA PAGE = 0 /* Allocate IQ math areas: */ IQmath : > FLASHC PAGE = 0 /* Math Code */ IQmathTables : > 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 : > IQTABLES2, PAGE = 0, TYPE = NOLOAD { IQmath.lib<IQNexpTable.obj> (IQmathTablesRam) } */ FPUmathTables : > FPUTABLES, PAGE = 0, TYPE = NOLOAD /* Allocate DMA-accessible RAM sections: */ DMARAML4 : > RAML4, PAGE = 1 DMARAML5 : > RAML5, PAGE = 1 DMARAML6 : > RAML6, PAGE = 1 DMARAML7 : > RAML7, PAGE = 1 /* Allocate 0x400 of XINTF Zone 7 to storing data */ ZONE7DATA : > 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 : > RESET, PAGE = 0, TYPE = DSECT vectors : > 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 }
可以看到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 : > RAML4, PAGE = 1
通过以上几条语句,笔者实现了将变量的内容存放入指定的RAML4存储空间的操作。
从上可以得出,当全局变量所占内存过大时,我们可以通过自定义段选择有所余裕的存储空间的方式,从而来解决内存不足的问题。
以上是Linux中cmd檔的作用是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!