Andes SAG 應用實例

Facebook
Twitter
LinkedIn

  在嵌入式開發中,系統軟體設計特別是各種記憶體的規劃是必不可少的一個環節,它也直接體現在連結腳本的撰寫上。因連結腳本的語法相對複雜和篇幅較大,前期撰寫和後期維護對工程師來講難度都很大, 但對使用 AndesCore 做開發的工程師來講,Andes SAG 是一大福音,它提供簡單直觀的描述語言替代了複雜的 linker script。我們收到的回饋也證明,越來越多的工程師開始採用 Andes SAG 替代 linker script,之前我們有一篇技術文章對 SAG 的語法格式做了介紹並說明如何使用,本文將展示四個實際專案開發的例子,以幫助廣大開發者更好的熟悉和理解 Andes SAG,同時可以作為開發時的參考。

1. 將函數和變數指定到特定位址
  第一個例子是如何將函數和變數的位址指定到一個特定的位址上。有這樣要求的原因有很多,諸如 SOC 的執行位址空間不連續,或者需要高效使用某一塊效率很高的記憶體等情況。解法分為兩步:一,在 SAG 檔中添加自訂的 section, 將此 section 的 VMA 設定到指定地址;二,在 C 語言中,將需要改變的函數和變數用特定的語法放在自訂的 section。

  圖表 1 是在SAG 中自訂section 的例子。第 1 行關鍵字 USER_SECTIONS 表示後面接的這幾個 sections 都是由使用者自訂的 sections。

  圖表 1 中,第 4 行至 8 行表示從 0x0 開始的區域是唯讀區,包含程式碼(.text section)及唯讀資料段(.rodata section)。第 9 行,MYRAM0 部分表示.mysection0 的 VMA 從 0x00014000 開始。以此類推,MYRAM1 和 MYRAM2 部分各自表示mysection1 和.mysection2 的 VMA 起始位置,因為 LMA 與 VMA 不一致,所以需要做 copy LMA 位址至 VMA 位址的工作。第 21 行的 RAM1 裡放的是.data 及.bss sections,執行時期會從 0x00010000 開始,原始程式碼中須做到將 data 從LMA 位址複製至  VMA 位址,可以使用,可以使用 __data_lmastart 與 __data_start 來定址。

  指定函數放在自訂 section 裡,在原始程式碼的對應處要使用    attribute    ((section(“.mysection0”)))語法,完整寫法請參考圖表 2a。圖表 2b是另外一種寫法。

  指定全域變數 gdata1 放在自訂 section .mysection1 裡,在原始程式碼的對應處要使用   attribute   ((section(“.mysection1”)))語法,完整語法請參考圖表3。

  將函數和變數這樣指定後,編譯後的 elf 執行檔可以清晰看到對應 Section 的 LMA 與 VMA 如圖表 4.

2. 實現 IVB 在執行時切換
  有一個客戶需要系統在開機與正常執行時能有不同的 ISR,即是同一個中斷的服務函數在開機和正常執行時會不一樣。對於這個問題的解法有很多,我們今天介紹是其中一種解決方法:設置一個新的 Vector Table,新的 Vector Table 會跳到新的 ISR;通過 SAG 將新的 Vector Table 指定到一個特定位址上;當程式開機完成,需要正常執行時,只需要去修改 IVBASE (ir3)這個寄存器。
  所以完成這個例子的重點是如何在組合語言程式碼中建一個新的 vector table 並指定到自訂的 section 中。表5是實例的寫法:

  圖表 5 重點是是第一行,.section 是用來定義非標準的 section,.nds32_aa 即為非標準 section 的名稱,”a”表示 allocable, “x”表示 executable. 因為 Andes 的標準 vector table 一般會放在.nds32_init section,所以新的 vector table放.nds32_aa 裡,名稱不一樣能區別就好。接下來是讓新的自訂 section .nds32_aa 執行在特定位址上,如圖表 6 所示。

  這樣新的 vector table 的首位址會被固定到 0x10000 的位置,當程式開機完成,只需要將 IVBASE 設定到這個位址,那麼當有中斷進來,就會跳到新的 Vector Table 中。

3. 指定一個或幾個 C 檔的所有 section 到指定位址
   上兩個例子有共同點是通過程式設計將某一段程式放到自訂 section,區別在於一個是指定 C 語言函數和變數到自訂 section,一個指定組合語言函數到指定的 section,都需要改動原始程式碼。然而對於一些應用場景,比如不提供原始程式碼只有編譯好的.o 或者.a 檔,如果想將.o 檔裡的 section 指定到特定位址執行,這個時候該如何做呢?請參考圖表 7A 的寫法,這表示我們要將 hello.o 的唯讀區,包含程式碼(.text section)及唯讀資料段(.rodata section)放在 LMA 及VMA 在 0x10000 的地址上。

  在整個 project 中如果將每個.o 檔都列出來,那麼整個 SAG 文檔將變得難以閱讀,而且在給後期維護帶來麻煩,這種解法不好。如果使用者只需要排除幾個.o 檔,對於熟悉 GNU linker 的讀者會想到“EXCLUDE_FILE”這一語法,讓使用者可以很方便地在 Linker script 中實現這一需求。Andes SAG 也與時俱進地引入這一語法。圖表 7B 正是這樣一個例子,它將 uart.o 中所有的 section 都放到一個特定位址去執行,因為 LMA 與 VMA 不一致,所以需要將 LMA 位址上的程式碼複製到 VMA 位址,而其它的保持不變,且可正常執行。

圖表 7B 支援“EXCULDE_FILE”

4. 如何避免 LMA 或 VMA 的偏差
  在前三個例子中,都是舉例去說明如何實現將程式的某一部分的 LMA 或者 VMA 固定在某一個特定位址上,這是對 linker script 的基本要求。嵌入式軟體工程師需要知道,當某一 section 的 LMA 與VMA 不相等時,那麼在程式初始化時需要將這一 section 從LMA 的位址複製到 VMA 的位址。初始化做複製時,這些 section 的LMA 和VMA 都是在 linker script 中給定值的,代碼中只是去做引用。 Andes SAG 同樣可以給變數 LMA 和 VMA 給予定值,但如何定值呢,是不是一個一個緊湊地排列下來?答案很顯然是不。很多工程師都知道,資料存放有Alignment 的要求,比如 4 Byte 的Word 其存放的首位址需要是 4 Byte Align; 程式呢,因為最佳化的需要,比如在 Andes 編譯器在-O3 等級下,函數的首位址同樣強制 4 Byte Align。既然有對齊的要求,就必然有 gap 存在,當然這裡舉出的對齊因素只是讓讀者瞭解到連結器對某一 section 的LMA 或VMA 的數值確定不只是單純累加,Andes SAG 能自動處理好大部分對齊狀況。但在一些較複雜的例子中,需要給 Andes SAG 更多指示,讓它工作正確。

  首先,我們來看圖表 7 所舉出的例子,這一行“LOADADDR NEXT__uart_lmastart”,有一個關鍵字“NEXT”。它的作用就是讓 SAG 知道,這個變數的取值是下一個 Section 的開始,而不是上一個 Section 的結束。為了讓讀者更明白所表示的含義,我們首先來看依照圖表 7 的 SAG 編譯出的 elf 執行檔 header 資訊,如圖表 8:

  可以看到.text_*uart.o 的 LMA 應該是 0x1c60, 上一個 section(.bss)的LMA 結束地址應為:0x1c48+0x10=0x1c58,所以為了清晰地讓 SAG 知道    uart_lmastart 代表.text_*uart.o 的LMA 開始而不是.bss 的 LMA 結束,我們應該用 NEXT 去修飾它。

  然後,我們再來看圖表 9 的例子,這個例子中,使用“LMA_FORCE_ALIGN 的原因是因為可能某一個 section 的 size  只有 2 Byte(不是 4 Byte 的整數倍),但下一個 section 的 VMA 起始位址需要 4 Byte Align,這時就會出現衝突,為解決衝突,Andes SAG 引入這一關鍵字“LMA_FORCE_ALIGN”,強制讓 LMA 與 VMA 用同一個值去做 Align。

  我們用圖表 9 的 SAG 例子去編譯對應的 project,可以看到圖表 10 中 section .sbss_b 的 LMA 已經被從 0x1d42 調整到 0x1d44。

5. 結語
   Andes 提供簡單易用的 SAG 工具幫助工程師替代了複雜的 linker script,可以大大提高在 Andes core 平臺上的軟體發展效率。本文從實際例子出發,介紹了 Andes SAG 工具如何快速解決工程實際問題,說明了 Andes SAG 強大而且容易上手。然而工具的功能越強大,也就需要工程師多加深入瞭解功能設計的緣由,這也正是最後一個例子展現出來的道理,即是透徹瞭解就可以熟能生巧。希望廣大讀者能熟練掌握 Andes SAG 這樣一把利器,在軟體發展中發揮四兩撥千斤的作用。

參考文檔:
 1: BSP321 programming guide link generator
 2: The GNU Linker Manual