EABI和OABI
作者:曹忠明,華清遠見嵌入式學院講師。
相信很多學習嵌入式linux的人都碰到過這樣一個問題:
初學linux的時候大家都用的工具鏈版本多是3.4.5或3.4.2,名字爲arm-linux-gcc或arm-softfloat-linux-gnu-gcc,可突然有一天發現這幾個版本的編譯器無法編譯最新的內核了,並且發現人們都換了工具鏈了(arm-none-linux-gnueabi-gcc),怎麼辦,換唄。於是也都換成了這個工具鏈,編譯內核,製作跟文件系統,按部就班的做,和以前沒什麼區別,很多人甚至想這些操作我都做爛了,閉着眼睛都能完成,一切和以前也沒什麼區別。可是緊接着問題來了,當內核啓動到最後階段掛載文件系統是出現如下錯誤:
kernel panic:attempted to kill init
或者什麼錯誤都不提示,只是永遠進入不了終端。
這是什麼問題呢,答案是大家需要在內核配置的時候選擇上如下內容:
make menuconfig
Kernel Features --->
[*] Use the ARM EABI to compile the kernel
[*] Allow old ABI binaries to run with this kernel (EXPERIMENTAL)
選上這兩項重新編譯內核,發現上面提到的問題就解決了,爲什麼呢,這兩個選項是什麼東西呢。在這裏得提到幾個概念:
ABI:application binary interface
OABI:old application binary interface
EABI:extended application binary interface
但上面兩項選中後在內核的配置文件.config中CONFIG_AEABI和CONFIG_OABI_COMPAT會被設置爲“y”,CONFIG_AEABI表示現在內核爲EABI,CONFIG_OABI_COMPAT表示兼容OABI。
爲什麼這兩個選項會影響到我們的系統啓動呢。
這兩個選項可以選擇任意一個也可以都選。這裏涉及到兩個結構sys_call_table和sys_oabi_call_table,這兩個表是一個內核的跳轉表,存放的是系統調用的指針。當CONFIG_AEABI和CONFIG_OABI_COMPAT都選中的時候,當應用程序使用OABI的是時候調用sys_oabi_call_table中的系統調用,應用程序使用EABI時使用sys_call_table中的系統調用。而如果只選CONFIG_AEABI則使用sys_call_table。兩個都不選則使用sys_call_table。應爲CONFIG_OABI_COMPAT對CONFIG_AEABI有依賴關係所以不能只選擇CONFIG_OABI_COMPAT。
可以參考如下代碼
arch/arm/kernel/entry-common.S
#if defined(CONFIG_OABI_COMPAT)
/*
* If we have CONFIG_OABI_COMPAT then we need to look at the swi
* value to determine if it is an EABI or an old ABI call.
*/
#ifdef CONFIG_ARM_THUMB
tst r8, #PSR_T_BIT
movne r10, #0 @ no thumb OABI emulation
ldreq r10, [lr, #-4] @ get SWI instruction
#else
ldr r10, [lr, #-4] @ get SWI instruction
A710( and ip, r10, #0x0f000000 @ check for SWI )
A710( teq ip, #0x0f000000 )
A710( bne .Larm710bug )
#endif
#ifdef CONFIG_CPU_ENDIAN_BE8
rev r10, r10 @ little endian instruction
#endif
#elif defined(CONFIG_AEABI)
/*
* Pure EABI user space always put syscall number into scno (r7).
*/
A710( ldr ip, [lr, #-4] @ get SWI instruction )
A710( and ip, ip, #0x0f000000 @ check for SWI )
A710( teq ip, #0x0f000000 )
A710( bne .Larm710bug )
#elif defined(CONFIG_ARM_THUMB)
/* Legacy ABI only, possibly thumb mode. */
tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs
addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in
ldreq scno, [lr, #-4]
#else
/* Legacy ABI only. */
ldr scno, [lr, #-4] @ get SWI instruction
A710( and ip, scno, #0x0f000000 @ check for SWI )
A710( teq ip, #0x0f000000 )
A710( bne .Larm710bug )
#endif
#ifdef CONFIG_ALIGNMENT_TRAP
ldr ip, __cr_alignment
ldr ip, [ip]
mcr p15, 0, ip, c1, c0 @ update control register
#endif
enable_irq
get_thread_info tsk
adr tbl, sys_call_table @ load syscall table pointer
ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing
#if defined(CONFIG_OABI_COMPAT)
/*
* If the swi argument is zero, this is an EABI call and we do nothing.
*
* If this is an old ABI call, get the syscall number into scno and
* get the old ABI syscall table address.
*/
bics r10, r10, #0xff000000
eorne scno, r10, #__NR_OABI_SYSCALL_BASE
ldrne tbl, =sys_oabi_call_table
#elif !defined(CONFIG_AEABI)
bic scno, scno, #0xff000000 @ mask off SWI op-code
eor scno, scno, #__NR_SYSCALL_BASE @ check OS number
#endif