連接腳本主要做用是描述輸入文件的section是如何映射到輸出文件的內存佈局中。通俗的講法就是編譯完成後的各個obj文件,按照哪一種順序放與bin的哪一個地址中;同時將運行時變量符號與VMA關聯。
主要參考了下邊幾個博客:
1. 連接腳本的 __attribute__ 屬性
2. GNU-ld連接腳本淺析html
主要目的是能夠將變量或函數,運行時連接到用戶定義的區域中,好比SRAM,某些CPU比直接放在FLASH中運行快(不必定,好比STM32,片內FLASH在ICODE總線上,指令預取功能使能將實現相似多級流水線的操做,SRAM則再也不ICODE上,須要 "取指->譯碼->執行"沒法加速。
主要使用連接腳本語法有:
MEMORY命令定義存儲區域,經過輸出section描述的 >REGION 顯式的將該段限定到具體的存儲區域。 以下:最後的區域爲stm32f746ng最後64k,用來存放測試的變量。函數
MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 960K USER_AREA(rx) : ORIGIN = 0x80F0000, LENGTH = 64K }
在連接腳本的SECTIONS 段內添加下列描述:oop
_siusrdata = LOADADDR(.usrdata); /* LOADADDR描述了.usrdata段的LMA,可在程序中聲明:extern char _siusrdata; 使用時只能只用_siusrdata的地址:char *src = &_siusrdata; src實際等於0x80F0000*/ .usrdata : { . = ALIGN(4); _susrdata = .; /* create a global symbol at usrdata start;VMA地址*/ *(.usrdata) /* .usrdata sections */ *(.usrdata*) /* .usrdata* sections */ . = ALIGN(4); _eusrdata = .; /* define a global symbol at usrdata end */ } >RAM AT> USER_AREA
主程序中在聲明處使用 attribute屬性聲明section, 使用extern 聲明連接腳本中的變量:佈局
int data_usrarea __attribute__((section(".usrdata"))) = 6666 ; extern char _siusrdata,_susrdata,_eusrdata;
使用時:測試
printf("usrarea LMA = %X, VMA = %X\r\n", &_siusrdata, &_susrdata); printf(usrdata addr = %X, value=%d\r\n", &data_usrarea,data_usrarea);
打印結果以下:ui
usrarea LMA = 80F0000, VMA = 20000070 usrdata addr = 20000070, value=-536140031
地址是對的,可是value怎麼是錯的,實際是由於,咱們自定義的區域並沒有本身將數據加載到正確的VMA地址。而系統默認的.data區域是由系統啓動時加載的,不一樣的工程實現方法不一樣,如stm32 cubumx 生成的makefile工程中是這樣作的.net
Reset_Handler: ldr sp, =_estack /* set stack pointer */ /* Copy the data segment initializers from flash to SRAM */ movs r1, #0 b LoopCopyDataInit CopyDataInit: ldr r3, =_sidata ldr r3, [r3, r1] str r3, [r0, r1] adds r1, r1, #4 LoopCopyDataInit: ldr r0, =_sdata ldr r3, =_edata adds r2, r0, r1 cmp r2, r3 bcc CopyDataInit ldr r2, =_sbss b LoopFillZerobss
這段彙編的目的就是加載.data區至SRAM中,即已初始化的全局變量區。咱們也能夠在彙編中添加本身的代碼,可是最好仍是在main函數中去實現不破壞原有文件的完整性。unix
char *srcdata_ptr = &_siusrdata; char *dstdata_ptr = &_susrdata; while(dstdata_ptr < &_eusrdata) { *dstdata_ptr++ = *srcdata_ptr++; }
添加上述代碼完成.usrdata區域從 LMA處加載到VMA處,之後就能夠快樂的運行了,打印信息以下。code
usrarea LMA = 80F0000, VMA = 20000070 usrdata addr = 20000070, value=6666
思考,有了這個功能,實際上咱們能夠將程序分段更新,如定義一些配置參數存放在特定區域,而後在更新時能夠直接這個區域更新。更加靈活的完成在線升級。htm