GNU連接腳本使用

GNU連接腳本使用


連接腳本主要做用是描述輸入文件的section是如何映射到輸出文件的內存佈局中。通俗的講法就是編譯完成後的各個obj文件,按照哪一種順序放與bin的哪一個地址中;同時將運行時變量符號與VMA關聯。
主要參考了下邊幾個博客:
1. 連接腳本的 __attribute__ 屬性
2. GNU-ld連接腳本淺析html

使用案例

1. 將變量或函數存放在用戶定義的區域

主要目的是能夠將變量或函數,運行時連接到用戶定義的區域中,好比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

相關文章
相關標籤/搜索