本文介紹了C6000最新的v7.2或者之后的編譯器如何支持ELF(EABI)和COFF-ABI格式,首先由ARM引入嵌入式(Embedded) EABI的介紹,之后比較了COFF-ABI和EABI的區(qū)別,如何用編譯器選項(--ABI=EABI --strip_coff_underscore)和預(yù)編譯處理命令來實現(xiàn)從COFF格式到ELF格式的轉(zhuǎn)換,主要是關(guān)注long數(shù)據(jù)類型位寬不一致以及匯編文件變量和函數(shù)定義的前置下劃線的處理方式。最后是ELF格式引入的鏈接段區(qū)和COFF格式的不同。 EABI簡介 ABI的定義:ABI代表應(yīng)用程序二進制接口(Application Binary Interface).ABI是一套編譯器遵循的規(guī)則,因此單獨編譯的對象模塊和庫可以鏈接成可執(zhí)行文件。這些規(guī)則包括許多細節(jié)。例如:
COFF ABI和EABIC6000 編譯器在版本7.2.x之前的版本支持COFF的ABI,從編譯器版本v7.2.x 開始,C6000 編譯器繼續(xù)支持COFF,但也通--abi=eabi編譯選項支持新的 EABI,除了mv6600外,其他默認的都是COFF ABI。而mv6600的默認為EABI格式。 EABI的定義EABI代表Embedded ABI。安騰 64 (Itanium 64 IA64) 是英特爾 CPU 體系結(jié)構(gòu)。雖然今天不廣泛使用,但一個非正式小組的還是為該體系結(jié)構(gòu)建立了一套c++ ABI。IA64 ABI成為為整個GPP 社區(qū)的C/C++編譯器事實上的標準。許多 GPP工具集提供的現(xiàn)代編譯器功能依賴此ABI。TI 編譯器也引入IA64 ABI的ABI。ARM為ARM CPU 體系結(jié)構(gòu)建立的名為AEABI。AEABI的目的是允許從不同的編譯器供應(yīng)商鏈接在一起并在ARM 系統(tǒng)上執(zhí)行代碼。TI ARM 編譯器 v4.4.0 引入了對支持開關(guān)--abi=eabi。 ELV vs EABI實現(xiàn)ELF是目標文件格式。EABI是一種ABI。ELF目標文件格式是EABI引入的最大的變化。 http://processors.wiki./index.php/C6000_EABI:Introduction_to_EABI C6000編譯器支持ELF格式的EABI C6000編譯器支持ELF格式的EABI,包括如下特性 全局變量在main函數(shù)運行前初始化為0; 動態(tài)鏈接,很方便的在運行系統(tǒng)中加入算法; 原生的ROM:創(chuàng)建和鏈接ROM的代碼; GPP樣式的32-bit long:方便移植算法到通用處理器 更快的鏈接: 刪除復(fù)制的debug信息 全局變量的初始化的壓縮:節(jié)省用于初始化的表格; C++的支持 有效的小類:加速C++的運行; 加快模板的實例和函數(shù)內(nèi)聯(lián); 引入沒有運行時額外開心的異常 更小的虛擬表節(jié)省空間
而COFF格式到EABI格式的轉(zhuǎn)換也是非常容易的,在7.2之后版本的編譯器通過編譯選項就能完成。詳細的可以參考 http://processors.wiki./index.php/C6000_EABI_Migration.
C6000編譯器EABI格式支持 C6000 EABI 7.2.X 引入了新的基于 ELF的ABI,C6000嵌入式應(yīng)用程序二進制接口應(yīng)用程序報告(SPRAB89) 中,可以找到C6000 EABI實現(xiàn)的詳細信息。TMS320C6000 優(yōu)化C編譯器用戶指南中可以找到的文檔所述的功能(SPRU187,修訂P或更高版本)和TMS320C6000 匯編語言工具用戶指南(SPRU186,修訂R或更高版本)。 最常見的用戶EABI轉(zhuǎn)換問題 大多數(shù)用戶只需要執(zhí)行幾個到他們從 COFF 移到ELF的代碼更改。用戶很可能會遇到的最常見的問題是: 大小長已經(jīng)改變從 40 位到 32 位,和原生類型__int40_t 現(xiàn)在支持為 40 位計算。 COFF 符號名稱添加前導(dǎo)下劃線,但EABI實現(xiàn)不用。匯編文件引用符號將需要特殊處理。 COFF 支持將會被淘汰嗎? ELF和EABI實現(xiàn)將最終完全取代COFF和COFF ABI;然而COFF將繼續(xù)支持一段時間。COFFABI支持將慢慢地逐步取消。
轉(zhuǎn)換策略 首先考慮是否需要任何EABI實現(xiàn)功能。確認后再支持ELF和COFF格式。 COFF格式和ELF 格式庫 強烈建議發(fā)布COFF和ELF版本的庫。對可移植的C代碼,支持COFF和ELF的工作量很小,更重要的是處理匯編代碼,通常是使用條件編譯重命名全局符號。 預(yù)定義的符號: __TI_EABI__ 編譯器和匯編程序預(yù)定義符號 __TI_EABI__以指示在編譯源下EABI實現(xiàn)。使用--abi=EABI來指定該宏定義選項。 處理只有COFF格式的庫 沒有工具支持將COFF對象文件轉(zhuǎn)換為ELF文件,因而強烈建議您發(fā)布COFF和ELF版本的庫。 C和C++實現(xiàn)的更改 完全在C或C++編寫的程序非常容易轉(zhuǎn)換,只要滿足可移植的條件:
如果您的代碼可以避免這些可移植假設(shè),則可重用代碼,下面介紹EABI實現(xiàn)和 COFF ABI不同的C和C++語言的功能。 long int 類型為 32 位 根據(jù)需要EABI標準,long int的整數(shù)類型是 32位寬,但在COFFABI模型中是40比特位寬。可以采用新類型__int40_t來表示40位精度。當包括 stdint.h,可以使用 int40_t 類型。 40 位intrinsic內(nèi)部函數(shù)類型更改 C6000 EABI實現(xiàn)不支持 '長' 的本機 40 位整數(shù)類型,因為本機 40 位以下的內(nèi)部函數(shù)將有新的原型,利用 COFF 和EABI實現(xiàn)下的全力支持,__int40_t 的類型:
位字段布局 位字段聲明的類型是現(xiàn)在的容器類型。這意味著某些結(jié)構(gòu)在 COFFABI和EABI實現(xiàn)將會有不同的布局。對于必須是COFFABI和EABI之間的可移植代碼,不應(yīng)使用位域。如果必須使用它們,位字段可能需要使用不同的有條件地編譯代碼聲明。 C 和C++ 標準要求的位字段 位字段聲明的類型是出現(xiàn)在源代碼中的類型。為保存位字段的值,C 和C++ 標準允許執(zhí)行分配任何可尋址的足夠大存儲單元,不需要與聲明的類型相關(guān)。容器類型,通常稱為可尋址的存儲單元,是位字段如何包裝并對齊的主要決定因素。 C89、C99和C++對類型聲明有不同的要求:
在嚴格的C++,沒有l(wèi)ong long的類型,但是C99有它,因為C++編譯器通常支持它作為擴展名。C99標準不需要的位字段支持long或long long已聲明類型的實現(xiàn),但因為C++允許它,而常見的C編譯器并不能很好的支持它們。 TI 的編譯器支持在C和C++使用任何整型類型作為聲明的類型,但只針對EABI實現(xiàn)。ABI (coff),為位字段的聲明類型 為int,unsigned int,signed int。 EABI位域布局方案 為EABI實現(xiàn),聲明的類型也用作容器類型。這有兩個主要的后果:
如果 1比特位字段已聲明類型int,EABI為位字段分配int容器。其他字段可以共享該容器,但要保證為每個字段存儲在容器中完全相同的位字段的大小。 示例 1 (P 代表填充): 結(jié)構(gòu) S {int a:1 ;} ; 1111111111222222222233 01234567890123456789012345678901 aPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP (一個 32 位容器) 示例 2: 結(jié)構(gòu) S {int a:1 ; int b:1 ;} ; 1111111111222222222233 01234567890123456789012345678901 abPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP (一個 32 位容器 示例 3: 結(jié)構(gòu) S {char a:7 ; char b:2 ;} ; 111111 0123456789012345 aaaaaaaPbbPPPPPP (兩個 8 位容器) 4 示例: 結(jié)構(gòu) S {char a:2 ; short b:15 ;} ; 1111111111222222222233 01234567890123456789012345678901 aaPPPPPPPPPPPPPPbbbbbbbbbbbbbbbP (一個 8 位容器、 一個 8 位墊和一個 16 位的集裝箱) IA64C++ABI規(guī)格 (可以參考位字段布局http://www./public/cxx-abi/abi.html). COFF ABI布置方案 COFF ABI則使用不同的策略來處理位字段。它使用最小可能的空間,并將增長當前容器,如果不斷增加,以允許分配的當前位置的位字段。 示例 1: 結(jié)構(gòu) S {int a: 1 ;} ;01234567 aPPPPPPP (一個 8 位容器) 示例 2: 結(jié)構(gòu) S {int a: 1 ; int b:1 ;} ;01234567 abPPPPPP (一個 8 位容器) 示例 3: 結(jié)構(gòu) S {char a: 7 ; char b:2 ;} ;111111 0123456789012345 aaaaaaabbPPPPPPP (一個 16 位容器) 4 示例: 結(jié)構(gòu) S {char a: 2 ; short b:15 ;} ;1111111111222222222233 01234567890123456789012345678901 aabbbbbbbbbbbbbbbPPPPPPPPPPPPPPP (一個 32 位容器) 更改代碼的匯編 (C 和C++ABI變化) C ABI是編譯器對C代碼程序的匯編表示。定義一個C可調(diào)用的函數(shù)或調(diào)用C函數(shù)的匯編代碼必須符合ABI。本節(jié)介紹由 C和C++ 的功能在匯編代碼中實現(xiàn)的方式更改而必須對匯編代碼的修改。 COFF下劃線名稱重整 COFF-ABI使用下劃線將匯編代碼的名稱空間和C代碼命名空間分開。C 編譯器將為每個外部可見的標識符加下劃線,這樣它將不會與匯編具有相同名稱的對象發(fā)生沖突。我們把這稱之為 COFF 下劃線. 例如,此源的代碼: int x ;int func (int y) {} 在ABI COFF 變?yōu)椋? .bss _x,4,4 _func: 請注意如何 C/C++的符號'x'已成為匯編的'_x'。 EABI實現(xiàn)不添加 COFF 下劃線。 這是一個通用的 ELF 要求。用戶負責確保不會沖突用戶定義的名稱。在EABI實現(xiàn)成為相同的源代碼: .bss x 4,4 func: 刪除 COFF 下劃線 COFF-ABI C和C++的符號,以與手動編碼的匯編避免名稱沖突添加前導(dǎo)下劃線,但EABI實現(xiàn)不添加此下劃線。因而需要修改COFF ABI 程序到EABI實現(xiàn)中的手動編碼的匯編文件中使用的函數(shù)和變量。 條件重定義方法 將與 COFF 和 EABIs 兼容的首選的解決方案是使用.asg 匯編程序指令EABI實現(xiàn)C名稱替換 COFF ABI 重整的名稱。 .if __TI_EABI__ .asg red_fish, _red_fish .endif
.global _red_fish
_red_fish: <start of function> 雙標簽法 另一個簡單的解決方法是提供兩個標簽,一個提供 COFF ABI名稱,另一個提供EABI實現(xiàn)名稱。 .global _red_fish、 red_fish _red_fish: red_fish: < 函數(shù)的開始 〉 向后兼容性: --strip_coff_underscore 對于匯編代碼不能輕易修改的項目,編譯器提供了--strip_coff_underscore 選項指示把COFFABI外部符號名稱翻譯為EABI,即去除一個前導(dǎo)下劃線。此選項僅對手代碼的匯編文件和從線性匯編文件的編譯器生成的匯編文件生效。此選項不會影響C和C++源代碼,編譯器生成的匯編文件,也不會采取影響鏈接器命令文件中。 例如,使用此源代碼: main.c: int main () {red_fish() ;} fish.asm: .global _red_fish _red_fish:... 對于 COFFABI在命令行上輸入: cl6x main.c fish.asm -z 為EABI實現(xiàn)在命令行上輸入: cl6x main.c fish.asm --ABI=EABI --strip_coff_underscore -z 鏈接器命令文件的更改 從COFF移植到EABI實現(xiàn)最有可能的步伐,用戶將需要進行更改時鏈接器命令文件。鏈接器支持鏈接器命令文件預(yù)處理。請參閱 C6000 匯編語言工具用戶指南。 EABI實現(xiàn)段 EABI實現(xiàn)重復(fù)利用 COFF ABI所使用的大多數(shù)編譯器生成的段名稱,還引入了新的段名稱。每個段需要分配給相應(yīng)的內(nèi)存。請參閱 下面 生成工具套件的所有部分。 DP 相對數(shù)據(jù)節(jié) EABI實現(xiàn)引入以下DP相對數(shù)據(jù)節(jié):
這些部分,則類似于.bss,只是它們初始化包含在對象文件中的數(shù)據(jù)。三個 DP 相對部分必須是連續(xù)的,這最容易通過使用鏈接器命令文件中的組: GROUP (NEAR_DP_RELATIVE) { .neardata .rodata .bss } > BMEM 編譯器v7.2中的鏈接器將自動創(chuàng)建上述組并分配給 BMEM,如果鏈接器命令文件具有以下: .bss > BMEM 只讀段 EABI實現(xiàn)引入了以下的只讀部分
.init_array段和.pinit功能類似,但EABI實現(xiàn)不使用名稱.pinit。 讀寫部分 EABI實現(xiàn)引入了讀寫以下各節(jié):
V7.2 鏈接器將分配 ELF 節(jié).fardata.far 段來實現(xiàn)EABI轉(zhuǎn)換。 沒有前置下劃線 任何引用或鏈接器命令文件中的定義將需要更改。例如,要將符號設(shè)置為main函數(shù)。 ABI (COFF): mainaddr = _main ;_symbol = 0x1234 ; EABI實現(xiàn): mainaddr = main ;symbol = 0x1234 ; C6x EABI實現(xiàn)段 圖1. C6000目標文件EABI鏈接段區(qū)含義 Reference: http://processors.wiki./index.php/C6000_EABI_Migration http://processors.wiki./index.php/EABI_Support_in_C6000_Compiler http://houh-1984.blog.163.com/ 本文介紹了C6000最新的v7.2或者之后的編譯器如何支持ELF(EABI)和COFF-ABI格式,首先由ARM引入嵌入式(Embedded) EABI的介紹,之后比較了COFF-ABI和EABI的區(qū)別,如何用編譯器選項(--ABI=EABI --strip_coff_underscore)和預(yù)編譯處理命令來實現(xiàn)從COFF格式到ELF格式的轉(zhuǎn)換,主要是關(guān)注long數(shù)據(jù)類型位寬不一致以及匯編文件變量和函數(shù)定義的前置下劃線的處理方式。最后是ELF格式引入的鏈接段區(qū)和COFF格式的不同。 |
|