c庫和嵌入式開發

來源:互聯網
上載者:User

 

引言

  隨著對高處理能力、即時多任務、超低功耗等方面需求的增長,高端嵌入式處理器已經進入了國內開發人員的視野,並在國內得到了普遍的重視和應用。 ARM是目前嵌入式領域應用最廣泛的RISC微處理器結構,憑藉低成本、低功耗、高效能等優點佔據了嵌入式系統應用領域的領先地位。ADS是ARM公司推出的ARM整合式開發環境,提供了對C和C++的支援,是目前開發ARM的主要工具。本文針對日益縮短的嵌入式開發週期,結合ARM系統開發調試經驗,對使用ARM標準庫進行應用程式開發作了比較系統的分析。

1  ARM標準庫介紹

  ADS提供了ANSI C和C++標準庫,本文僅討論ANSI C庫,該庫包含下面幾個部分:

  ◇ ISO C庫標準所定義的函數;
  ◇ 在semihosted環境下用來實現C庫函數與目標相關的函數;
  ◇ C和C++編譯器要使用的helper函數。

  該庫提供的諸如檔案輸入輸出之類的裝置,使用了標準的ARM semihosted執行環境(semihosting是針對ARM目標機的一種機制,它能夠根據應用程式代碼的輸入/輸出請求,與運行有調度功能的主機通訊,這種技術允許主機為通常沒有輸入和輸出功能的目標硬體提供主機資源)。ARMulator、Angel和MultiICE都支援這個環境,可以使用ADS中提供的開發工具開發應用程式,然後在ARMulator或者是開發板上運行和調試該程式。如果要使應用系統獨立於這個環境,則必須重新實現C庫中依賴於這個環境的相關函數,根據使用者系統的運行環境對C庫進行適當的裁減。

  使用ANSI標準C庫進行程式開發,不僅可以提高開發效率而且可以增強程式的可移植性。在程式中使用庫函數,必須先建立一個庫函數可以執行的環境,這些工作都由庫中的函數完成。當應用程式連結了C庫中的函數時,C庫中的函數將完成:

  ◇ 建立C程式所需的執行環境(建立棧,如果需要建立一個堆,初始化程式使用的部分庫);
  ◇ 調用main()函數開始執行C程式;
  ◇ 支援程式使用的ISO定義的函數;
  ◇ 捕獲運行時的錯誤和訊號,如果需要,根據錯誤終止執行或程式退出。

2  裁減ARM標準C函數庫

  標準庫中包含了部分依賴於ARM semihosted執行環境的函數,這部分函數的函數名中包含有單個或兩個底線“_”,需要重新實現這部分函數。如果在程式中定義這些函數,則編譯器就會使用新定義的函數,這個過程稱為庫函數的裁減。一般情況下,只需要重新定義很少的幾個函數就可以使用C庫。

  ARM應用系統開始執行使用者應用程式,必須先將應用程式載入到執行域,建立應用程式的執行環境。使用C庫時,這些繁瑣的工作就大部分由C函數來完成了。組譯工具完成系統初始化後,跳轉到C程式的入口__main()(注意:不是main(),當C程式中定義了main()主函數時,編譯器就會產生__main代碼)。由__main()引導庫函數完成C執行環境的初始化,具體過程如下:

  ◇ 將非啟動代碼的RO和RW執行域代碼從載入域地址複製到執行域地址;
  ◇ 將ZI域清零;
  ◇ 跳轉到__rt_entry。

  調用__main()將大大簡化彙編啟動代碼的編寫,彙編代碼僅需完成系統硬體的初始化,而沒有必要將代碼從載入域地址複製到執行域地址,以及 ZI域清零等工作。特別是當使用分布式載入時, __main()的作用就更加明顯了。但是__main()並沒有建立C庫運行必須的環境,這項工作由__rt_entry()完成,主要調用過程為:

  ◇ 調用__rt_stackheap_init()建立堆和棧;
  ◇ 調用__rt_lib_init()初始化引用的庫函數;如果需要,建立main()函數的參數argc和argv等;
  ◇ 調用main()函數,執行應用程式,可以應用庫函數;
  ◇ 用main()函數的傳回值作參數調用exit()。

  __rt_entry並不是C函數,它是用ARM C庫編程的起始點。__rt_entry不能用C語言實現,因為這時候堆棧還沒有建立,堆棧由__rt_stackheap_init()來建立。

main()函數是使用者代碼的進入點。它運行時要求應用程式的運行環境的建立,可以調用相應的輸入、輸出函數。在main()函數中,可以調用重新實現的C執行階段程式庫的函數來實現下面一些功能:

       ◇ 擴充資料棧和資料堆

       ◇ 調用需要回調的使用者定義的函數

       ◇ 調用使用LOCALE和CTYPE的C執行階段程式庫的函數

       ◇ 完成浮點的運算

       ◇ 調用進階及低級的輸入輸出的函數

       ◇ 產生運行錯誤資訊

 

上面簡單介紹了C程式使用庫函數時的調用過程,由__rt_stackheap_init()建立C庫使用的記憶體模型——堆和棧。因為ARM庫是建立在semihosted執行環境的,它實現的記憶體模型是基於這個環境的,所以必須修改這個記憶體模型建立機制。其中,必須重新實現的是__user_initial_stackheap(),因為預設的實現是基於semihosted執行環境的,該函數被__rt_stackheap_init()調用建立記憶體模型,其他兩個函數沒有預設的實現。

 __user_initial_stackheap()的函數原型為:__value_in_regs struct __initial_stackheap __user_initial_stackheap (unsigned  R0, unsigned SP, unsigned R2, unsigned SL)

  結構體__initial_stackheap在rt_misc.h定義如下:

struct __initial_stackheap
{
  unsigned heap_base, stack_base, heap_limit, stack_limit;
}

  實現該函數,必須滿足下面的條件:

  ◇ 使用不超過96位元組的棧空間;
  ◇ 除了R12(ip)外不要汙染其他寄存器;
  ◇ 將堆基址、棧基址、堆邊界和棧邊界分別存在R0~R3作為返回參數;
  ◇ 堆必須保持8個位元組對齊。

  實現常式如下:

#include <rt_misc.h>
__value_in_regs struct __initial_stackheap __user_initial_stackheap(
unsigned R0, unsigned SP, unsigned R2, unsigned SL)
{
  struct __initial_stackheap config;
  config.heap_base  = BASE_HEAP;/*堆基址 */
  config.stack_base = BASE_STACK;/*棧基址 */
  return config;
}

  為了提高應用程式開發效率和可移植性,希望在目標系統上使用ARM庫提供的標準輸入輸出庫函數。

  高層輸入輸出函數是不依賴於目標系統內容的,但是高層輸入輸出函數必須調用依賴於目標系統的底層函數,才能實現應用系統的輸入輸出。依據目標系統硬體環境重新定義這些底層函數,就可以使用庫提供的標準input/output庫函數了。下面以裁減ARM標準庫提供的printf系列輸出函數為例來作說明。

  標準I/O庫中最常用的是printf系列函數,包括_printf()、printf()、_fprintf()、fprintf()、 vprintf()和vfprintf()。所有這些函數非透明地使用__FILE,並且僅依賴於fputc()和ferror()兩個函數。函數 _printf()和_fprintf()與printf()和fprintf()的區別僅在於前兩個函數不能格式化浮點值。只要定義了自己的 __FILE版本和fputc()、ferror()函數,外加定義一個具有FILE類型的__stdout變數,就可以不作任何修改地使用printf
系列、fwrite()、fputs()和puts()函數了。

  下面給出了具體實現的模板,可以根據實際需要修改。

#include <stdio.h>
struct __FILE
{
  int handle;
  /*使用者需要的任何代碼(如果使用檔案僅是為了調試使用prinft在標準輸出端輸出資訊,則不需要任何檔案處理代碼)*/
};
FILE __stdout;/*FILE在stdio.h中定義為:typedef struct_FILE FILE;*/
int fputc(int ch, FILE *f) {
  /*使用者實現的fputc代碼。輸出一個字元,可以根據需要實現*/
  return ch;
}
int ferror(FILE *f) {
  /* 使用者實現的ferror代碼 */
  return EOF;
}

結語

  本文分析了ARM標準庫的工作機理,給出了裁減C庫進行程式開發的關鍵步驟。實際應用時需要根據具體的硬體環境和應用要求裁減C庫,提高代碼執行效率。

李宏:碩士生,主要研究方向為通訊抗幹擾技術、高速數傳、嵌入式系統在通訊中的應用。
楊飛:碩士生,主要研究方向為高速資料轉送。
張爾楊:博士生導師,主要研究方向為軟體無線電、系統類比、擴頻通訊、通訊抗幹擾技術、高速數傳及全數字接收機技術

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.