郝玉濤 孫建祥 安占新
1.中國載人航天工程辦公室,北京 100071 2.北京航天自動控制研究所,北京 100854
2017年俄羅斯研制的 “聯盟-2.1B”火箭在東方港基地發射,由于飛行軟件使用的發射場坐標參數是拜科努爾發射場的數據,導致火箭未能進入預定軌道,墜落大西洋[1]。由此可見,飛行軟件正確與否關系到運載火箭發射任務的成敗,確保飛行軟件執行程序的正確性是航天型號軟件設計人員致力解決的重要問題之一。
目前,航天控制領域廣泛使用德州儀器公司(Texas Instruments,簡稱TI) DSP(Digital Signal Processors)處理器進行控制計算。軟件設計人員通過集成開發環境CCS(Code Composer Studio)或者CC(Code Composer)生成COFF(Common Object File Format,通用對象文件格式)格式的飛行軟件,再通過其配套的轉換工具,生成自舉表(Boot Table)格式的文件,固化在計算機的FLASH中。計算機上電后,通過自帶的bootloader引導程序,自動加載自舉表格式的文件運行[2]。自舉表格式的執行程序能夠滿足運載型號部分計算機上電自動引導的需求,但不能滿足型號部分計算機需要通過二次引導程序[3-4]運行的需求。自舉表格式的文件不僅包含DSP執行程序,還帶有其它額外信息。二次引導的目標文件(DSP執行程序)不允許帶有這些額外信息。
為了滿足通過二次引導程序運行的需求,需要生成二進制格式的DSP執行程序。以往,軟件設計人員主要采用2種人工提取方法:(1)通過集成開發環境控制仿真器,將COFF格式的目標文件下載到DSP處理器中,再按照MAP文件(用于表示程序、數據以及IO空間的映射)中的代碼段以及初始化數據段地址,提取相應內存中的執行程序以及初始化數據;(2)軟件設計人員人工分析COFF格式的文件,在文件中提取出代碼段以及初始化數據段。這兩種人工生成執行程序的方法使用設備多,環境復雜,操作繁瑣,易出錯,可靠性低。
文獻[2]研究了DSP處理器引導功能的軟硬件配置設計以及引導控制程序;文獻[3]研究了基于二次引導程序的在線升級程序的方法;文獻[4]研究了多核DSP的加載方法和流程;文獻[5]研究了COFF文件向自舉表文件的轉換方法以及基于FLASH的自動加載方法;文獻[6]研究了基于外部擴展FLASH存儲器的程序代碼自舉加載方法。目前針對二次引導的目標文件如何可靠提取,沒有相關文獻進行論述。本文提出了基于COFF和自舉表(Boot Table)格式文件的DSP執行程序提取器設計方案及實現技術,不僅解決了文獻[2-6]中二次引導的目標文件自動提取問題,提高了生成效率和正確率,而且通過加殼技術[7],在目標文件中增加了DSP執行程序的CRC校驗信息,提高了飛行程序使用的可靠性。
本文研究了COFF文件、自舉表文件的格式,提出了基于上述兩種文件提取DSP執行程序的算法,介紹了軟件實現技術、功能驗證、性能評估以及在航天重大工程中的應用情況。
通用對象文件格式COFF是一種很流行的對象文件格式,是程序源代碼通過集成開發環境進行編譯、鏈接之后,最終產生的一種模塊化的文件格式。這種文件格式引入了“段”的機制,不同的目標文件可以擁有不同數量以及不同類型的段,為軟件開發人員提供了一組二進制接口定義,這些接口可以延伸到多種操作環境,從而減少重新編碼、重新編譯程序的需要。
COFF文件包括文件頭、可選文件頭、段頭信息表、段數據、重定位信息、行號入口表、符號表、字符串表[5]。其中段頭信息表、段數據、重定位信息、行號入口表對應多個段;文件頭、可選文件頭、段頭信息表、段數據與生成執行程序密切相關。
文件頭用來保存COFF文件的基本信息,如段頭的數目、時間戳、符號表位置、屬性標記等,共占用22字節,其中第2、3字節指明了段頭的數目。
可選頭在文件頭后面,從COFF文件的0x16偏移處開始,長度為28個字節,用來保存在文件頭中沒有描述到的信息,如執行代碼的大小、初始化數據的大小、未初始化數據的大小、程序入口地址、執行代碼的開始地址、初始化數據的開始地址等。
從第51字節開始,為各段段頭信息表,用來描述段信息,每個段都有一個段頭信息表來描述,段的數目在文件頭中指出。每個段頭信息表共48個字節,內容包括段名、段數據載入內存時的物理地址、段數據載入內存時的虛擬地址、段數據的實際長度、段數據在COFF文件中的偏移量、段屬性。第9~12字節為此段在內存中的物理地址;第21~24字節為此段程序或者數據在COFF文件中的偏移地址;第41~44字節為段屬性。段屬性為0x00000020時,表示此段是執行代碼段;為0x00000040時,表示此段是初始化數據段;為0x00000080時,表示此段是未初始化的數據段。
段數據用來保存各個段的數據,不同類型的段,其數據的內容和結構也不相同。在目標文件中,這些數據都是原始數據,無特別的格式。
在DSP系統中通常使用FLASH存儲器保存程序,在上電或者復位時,BootLoader引導程序將存儲在FLASH中的程序搬移到DSP片內或者片外RAM中,并跳轉到用戶程序入口運行,這個程序搬移過程叫自舉加載。用戶程序與一些必要的引導信息結合在一起,形成特定格式的自舉表,以便BootLoader引導程序在自舉加載過程中識別有效的用戶程序、搬移地址以及程序入口地址。
自舉表可以通過集成開發環境提供的工具生成,其過程為:(1)使用hex.exe工具,將集成開發環境生成的COFF格式文件轉換成為工具能夠識別的hex文件格式,轉換前需要配置好程序引導地址、程序入口地址;(2)使用hexbin.exe工具,將hex格式文件轉換為自舉表格式文件。
自舉表格式[6]文件包括內存寬度、STRB控制寄存器數值、數據塊,其中數據塊可以有多個,每個數據塊包括數據塊的大小、數據塊加載的起始地址以及數據。文件最后一個字數值為0,表示文件結束。
COFF文件解析器首先以二進制形式讀入擴展名為.out的COFF文件,分析COFF文件頭,其第2、3字節指明了段的數目;根據段數目,逐段分析段頭信息表,獲取每段的屬性標識,如果該段屬性為執行代碼或者初始化數據,記錄執行代碼段、初始化數據段內存中的物理地址、COFF文件中的偏移地址以及大小;計算執行程序(包含初始化數據)文件大小;計算執行代碼段、初始化數據段在執行程序文件中的位置,按照線性映射關系將此段數據存儲在相應內存中。COFF文件解析算法工作流程如圖1所示。

圖1 COFF文件解析算法工作流程
詳細過程如下:
1)采用WIN32提供的內存映射文件機制[8],根據可選頭中執行代碼、初始化數據段的大小,在內存中申請COFF文件相應大小的地址空間區域,將COFF文件中的數據以二進制形式讀入對應的地址空間區域。解析過程中直接讀取內存中相應地址獲取COFF 文件數據,不再對文件進行IO操作。
2)針對內存中的COFF文件數據,分析其文件頭,確定段數目:N。
3)逐段分析段頭信息表,如果該段屬性為0x00000020時,記錄此段內存中的物理地址MemAddrText_i、大小LenText_i、文件中的偏移地址FileAddrText_i(i=1,2,3,……);如果該段屬性為0x00000040時,記錄此段內存中的物理地址MemAddrInitData_j、大小LenInitData_j、文件中的偏移地址FileAddrInitData_j(j=1,2,3,…….)。
4)計算執行程序文件大小LenExeFile,并申請相應大小的地址空間區域,用來與執行程序、數據文件進行線性映射:
AddrLow=Min(FileAddrText_i,MemAddrInitData_j)(i=1,2,3,……,j=1,2,3,…,Min表示求最小值)。
AddrHigh=Max(FileAddrText_i,MemAddrInitData_j)(i=1,2,3,……,j=1,2,3,…,Max表示求最大值)。
LenExeFile=AddrHigh-AddrLow+LenLast(LenLast為通過Max獲得的起始地址最大的段的長度)。
5) 逐段分析段頭信息表,如果該段屬性為執行代碼或者初始化數據,計算此段數據在執行程序文件中的位置,按照線性映射關系將此段數據存儲在相應內存中:MemAddrSec_k(k=1,2,3,……)為執行代碼段或者初始化數據段內存中的物理地址, 執行代碼段或者初始化數據段在執行程序文件中的位置:
ShiftAddrSec_k=MemAddrSec_k-AddrLow(k=1,2,3,……)。
6)完成所有段的分析之后,按照線性映射關系將內存中的數據存儲在文件中,獲得執行程序文件。
自舉表文件解析器首先以二進制形式讀入自舉表文件,逐一分析各數據塊,獲取各數據塊的大小,據此計算執行程序文件的大小,并申請相應內存空間;根據各數據塊的大小、數據塊加載的起始地址,計算此段數據在執行程序文件中的位置,并將數據塊的數據按照計算的位置存儲在內存空間;將內存空間中的數據最終存儲在執行程序文件中。自舉表文件解析算法工作流程如圖2所示。

圖2 自舉表文件解析算法工作流程
詳細過程如下:
1) 讀入自舉表文件,獲取各段數據的大小LenSec_i(i=1,2,3,……),計算執行程序文件映射內存大小∑LenSec_i(i=1,2,3,……),申請相應空間,并清零。
2)重新讀取自舉表文件,跳過內存寬度和寄存器數值,指向第一個數據塊的信息頭,針對每一數據塊逐一進行3)~6)的處理。
3)判斷自舉表文件當前內容是否為0,為0,表示自舉文件結束,否則,表示仍有數據塊需要處理。
4)依次獲取本段數據塊的大小以及起始地址。
5)計算本段數據在執行程序文件映射內存中的相應位置,并將數據存儲在相應位置的內存中。
6)如果自舉表文件結束,則將內存中的數據存儲在執行程序文件中。
自舉表文件解析算法也采用WIN32提供的內存映射文件機制,其操作過程和方法與COFF文件解析算法相同。
本文以TI公司DSP為例進行說明,將集成開發環境CCS或者CC編譯、鏈接生成的COFF文件作為輸入文件,經過COFF文件解析器解析,生成執行程序;使用集成開發環境提供的hex.exe工具以及hexbin.exe工具,由COFF文件生成自舉表格式文件;自舉表格式文件經過其解析器解析,生成執行程序;為了提高生成執行程序的可靠性,對由COFF格式和自舉表格式文件生成的執行程序,通過二進制比較器進行逐字節比對,兩套執行程序大小、內容完全一致,則認為提取正確;最后通過二進制文件編輯器,使用加殼技術[7],在執行程序頭部增加長度和CRC校驗信息,生成帶CRC校驗信息的執行程序文件。軟件實現過程如圖3所。

圖3 軟件實現過程
在使用帶CRC校驗信息的執行程序文件前,可以根據長度、CRC校驗碼確認文件的完整性和正確性;使用時,通過脫殼技術[9],刪除CRC校驗信息和文件長度。帶CRC校驗信息的執行程序文件結構如圖4所示。

圖4 帶CRC校驗信息的執行程序文件結構
0~3字節,存放執行程序的長度(以字節為單位);4~5字節,填充0;6~7字節,存放執行程序的16位CRC校驗碼,計算CRC校驗碼的多項式為X16+X15+X2+1;從第8個字節開始,依次存放執行程序。
COFF目標文件包含text段、data段、bss段、const段、cinit段、switch段、stack段、system段、far段、sect指令定義的初始化段、usect指令定義的未初始化段等。這些段的含義如表1所示。其中text段、const段、cinit段、switch段以及sect指令定義的段為初始化段,需要提取到執行程序文件。

表1 COFF文件段的組成
在對提取器進行驗證時,測試用例考略了COFF文件的完整性、應用程序工程中鏈接文件定義段的隨機性、提取器軟件防錯處理等情況,共考慮10項內容、117個組合情況,設計用例519個。詳細情況如表2所示。

表2 提取器測試內容概況
針對使用提取器生成執行程序(以下簡稱方式一)、使用集成開發環境通過仿真器提取執行程序(以下簡稱方式二)、人工分析COFF文件提取執行程序,設計人員進行了生成正確率和性能對比分析。
在載人航天工程、探月工程、探火工程的新一代運載火箭型號的分系統綜合試驗、匹配試驗、出廠測試、靶場測試以及發射任務過程中,隨機選擇了80KByte~300KByte大小的執行程序、23位設計人員,初始化段和未初始化段隨機分配,每種狀態分別使用3種方式生成,每種方式均進行了200次,一次正確率(以往人工生成時,通過多次生成避免生成錯誤)測試結果如表3所示。

表3 一次正確率測試結果
上述測試過程中,記錄三種方式每次均提取正確的時間,隨機選擇100次的測試結果進行分析,如表4所示。

表4 性能測試結果
性能評估測試結果表明,通過提取器生成執行程序,不僅能夠確保100%正確生成,提高了生成正確率,而且將生成效率提高了約20倍。
以往人工生成DSP執行程序的方法使用設備多,環境復雜,操作繁瑣,易出錯,可靠性低。本文提出了基于COFF和自舉表文件的DSP執行程序提取器設計及實現技術,并在載人航天工程、探月工程、探火工程的新一代運載火箭型號中進行了廣泛應用。通過功能驗證、性能評估以及型號應用實踐,結果表明,使用提取器,能夠快速、自動生成帶有CRC校驗信息的DSP執行程序,該技術極大提高了DSP執行程序的生成效率、正確率、可靠性和使用安全性。