底層連結時報錯Unknown mandatory EABI object attribute 44,因為這個是使用NDK8.0 ARM 編譯的,而到linux下編譯
是使用prebuilt下的盒子編譯器,兩者都是ARM編譯器,上網搜都是說交叉編譯器使用的和底層不一樣。
第一部分:EABI 是什麼呢?
Embedded application binary interface, 即嵌入式應用二進位介面
EABI是新的“嵌入式”ABI(by ARM ltd)。EABI實際上是ABI的一個家族。對於Linux,GNU EABI也是一個subABIs。
與傳統的ABI比較明顯的更新包括:
A、支援軟體浮點和硬體實現浮點功能混用
B、系統調用的效率更高
C、後今後的工具更相容
D、軟體浮點的情況下,EABI的軟體浮點的效率要比OABI高很多,使用Vector Float Point(向量浮點),因此可以極大提高涉及到浮點運算的程式
兩種ABI在如下方面有區別:(OABI中的O,表示“Old”,“Lagacy”,EABI中的E,表示“Embedded”,是一種新的ABI)
A、調用規則(包括參數如何傳遞及如何獲得傳回值)
B、系統調用的數目以及應用程式應該如何去做系統調用
C、目標檔案的二進位格式,程式庫等
D、結構體中的 填充(padding/packing)和對齊
其實從百度查的資料說明: http://baike.baidu.com.cn/view/3547622.htm 其本質就是系統調用有本質的區別:
我們知道,sys_call_table 在核心中是個跳轉表,這個表中儲存的是一系列的函數指標,這些指標就是系統調用函數的指標,
如(sys_open).系統調用是根據一個調用號(通常就是表的索引)找到實際該調用核心哪個函數,然後運行該函數完成的。
首先,對於old ABI,核心給出的處理是給它建立一個單獨的system calltable,叫sys_oabi_call_table,這樣,相容方式下就會有兩個
system call table, 以oldABI方式的系統調用會執行old_syscall_table表中的系統調用函數,EABI方式的系統調用會用sys_call_table中的函數指標。
配置無外乎以下四種
第一 兩個宏都配置 行為就是上面說的那樣
第二 只配置CONFIG_OABI_COMPAT , 那麼以old ABI方式調用的會用sys_oabi_call_table,以EABI方式調用的 用sys_call_table,和1實質相同,只是情況1更加明確。
第三 只配置CONFIG_AEABI 系統中不存在 sys_oabi_call_table, 對old ABI方式調用不相容。只能 以EABI方式調用,用sys_call_table
第四 兩個都沒有配置 系統預設會只允許old ABI方式,但是不存在old_syscall_table,最終會通過sys_call_table 完成函數調用
連結工具命名:
arch-vendor-(os-)abi
1、arm-none-linux-gnueabi (ARM architecture, no vendor, linux OS, and the gnueabi ABI)
用於編譯ARM架構的u-boot、linux核心、linux應用等
2、arm-none-eabi
用於編譯ARM架構的裸機系統(包括linux的 boot、kernel)
3、arm-eabi
Android ARM 編譯器
第二部分:如何解決EABI的問題
1、浮點數問題
Makefile中參數意義:
-mabi=apcs-gnu :apcs-gnu是OABI的 參數,因此將OABI的參數傳給符合EABI標準的編譯,編譯階段沒有報錯,但在板上運行時,程式中涉及到浮點數的部分出現了許多莫名的問題。
比如 printf("%s %f",s,f);這句話輸出的浮點數值並不是傳給printf的參數,而是一個莫名其妙的數字。
解決辦法:在Makefile中將 “-mabi=apcs-gnu”去掉,重新編譯運行,成功!
編譯選項:
OABI: ABI flags passed to binutils: -mabi=apcs-gnu -mfpu=fpa
EABI: ABI flags passed by gcc to binutils: -mabi=aapcs-linux -mfloat-abi=soft -meabi=4
2、核心支援:需要核心同樣配置EABI編譯屬性才能支援EABI編譯出來的應用程式
make menuconfig
Kernel Features
[ ] Use the ARM EABI to compile the kernel
解決方案:將它尋上之後自動多出下面一行,這樣再次編譯的核心就ok了,嘿嘿:)
[*] Use the ARM EABI to compile the kernel
[*] Allow old ABI binaries to run with this kernel (EXPERIMENTAL)
3、使用NDK編譯的庫與在linux下編譯的庫link報錯
兩者使用使用同樣EABI選項但還是無是link成功,Unknown mandatory EABI object attribute 44
最後利用顯示動態庫載入並尋找函數符號解決問題。
由於需要明確需要找到的函數比較多,所以利用OpenGL匯出函數的方式來做。
定義entries.in檔案,用於放置所有需要匯出的函數
類似:
GL_ENTRY(void, glActiveTexture, GLenum texture)
GL_ENTRY(void, glAlphaFunc, GLenum func, GLclampf ref)
GL_ENTRY(void, glAlphaFuncx, GLenum func, GLclampx ref
#define GL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
定義此函數方便對於多參數的函數載入,可以省去很多麻煩
然後定義結構:
struct gl_hooks_t {
#include "entries.in"
};
範例代碼如下:
struct gl_hooks_t { #include "entries.in"}; char const * const gl_names[] = { #include "entries.in" NULL};/* This is a generic function pointer type, whose name indicates it must * be cast to the proper type *and calling convention* before use. */typedef void (*__eglMustCastToProperFunctionPointerType)(void);struct gl_hooks_t* g_hooks = NULL;void init_api(void *dso, char const * const * api,__eglMustCastToProperFunctionPointerType* curr) {while (*api) {char const * name = *api;__eglMustCastToProperFunctionPointerType f =(__eglMustCastToProperFunctionPointerType)dlsym(dso, name); *curr++ = f; api++; }}int load_library(const char*path,const char *sym){int status;void *dso = NULL; /* * load the symbols resolving undefined symbols before * dlopen returns. Since RTLD_GLOBAL is not or'd in with * RTLD_NOW the external symbols will not be global */dso = dlopen(path, RTLD_NOW);if (dso == NULL) {char const *err_str = dlerror();LOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");status = -EINVAL;}init_api(dso, gl_names, g_hooks);/* success */status = 0;done: if (status != 0) {if (dso != NULL) {dlclose(dso);dso = NULL;}}return status;}
這種方法最後在盒子上運行沒有問題,證明是可行的。