自己的内核支持低版本arm-linux-gcc静态编译的程序

目录:

一、艰辛的过程 2

1,问题显现 2

2,初步诊断 2

3ABIEABI 2

4OABIEABI兼容性 4

5,欢喜 11

6,重新陷入困境 12

7,最后的努力 12

8,成功啦 13

二、方法总结 14


一、艰辛的过程

1,问题显现

自己的内核是arm-linux-gcc 4.3.2编译的,hello程序是arm-linux-gcc 2.95.3静态编译的。把hello放入mini2440,运行。竟然没有显示出伟大的“hello world!”!郁闷~~~~

用友善的根文件系统,自己的内核,运行,还是没有显现。

用友善的根文件系统,友善的内核,运行,显现啦!奇怪!

用自己的根文件系统,友善的内核,运行,显现啦!咦?

看来是内核的问题!

用友善的配置文件,自己的内核源码,运行,显现啦!哇!

看来是内核配置问题!!

2,初步诊断

但是内核配置选项这么多,到底是那个配置信息呢???

一开始试图寻找自己的配置文件和友善的配置文件的不同点。但找了一个小时发现不同点实在太多了,而且从字面上也看不出什么联系来。

第一天,网上搜了好多好多资料,也没查出什么结果。后来仔细翻阅《【申嵌培训】Mini2440 Linux移植开发实战指南-内核部分2010-9-9.pdf2.3.2 关于ABI 和 EABI 这个小节,给了我启示!感谢申嵌大哥~~~~~

3ABIEABI

第二天,仔细搜了ABIEABI相关知识,有篇文章写得不错。网址如下:

http://bbs.chinaunix.net/thread-1950213-1-1.html

内容如下:

1。什么是ABI
ABIapplication binary interface (ABI),应用程序二进制接口。
既然是 接口,那就是某两种东西之间的沟通桥梁,此处有这些种情况:
A。应用程序 <操作系统;
B。应用程序 <(应用程序所用到的)库
。应用程序各个组件之间

类似于API的作用是使得程序的代码间的兼容,ABI目的是使得程序的二进制(级别)的兼容。

2。什么是OABI 和 EABI
OABI中的O,表示“Old”“Lagacy”,旧的,过时的,OABI就是旧的/老的ABI
EABI中的E,表示“Embedded”,是一种新的ABI
EABI有时候也叫做GNU EABI
OABIEABI都是专门针对ARMCPU来说的。

3EABI的好处 / 为何要用EABI
A。支持软件浮点和硬件实现浮点功能混用
B。系统调用的效率更高
C。后今后的工具更兼容
D。软件浮点的情况下,EABI的软件浮点的效率要比OABI高很多。

4OABIEABI的区别
两种ABI在如下方面有区别:
A。调用规则(包括参数如何传递及如何获得返回值)
B。系统调用的数目以及应用程序应该如何去做系统调用
C。目标文件的二进制格式,程序库等
D。结构体中的 填充(padding/packing)和对齐。
E
OABI
* ABI flags passed to binutils: -mabi=apcs-gnu -mfpu=fpa
* gcc -dumpmachine: arm-unknown-linux
* objdump -x for compiled binary:

private flags = 2: [APCS-32] [FPA float format] [has entry point]

* "file" on compiled Debian binary:

ELF 32-bit LSB executable, ARM, version 1 (ARM), for GNU/Linux 2.2.0, dynamically linked (uses shared libs), for GNU/Linux 2.2.0, stripped

* "readelf -h | grep Flags""

Flags: 0x0

EABI
* ABI flags passed by gcc to binutils: -mabi=aapcs-linux -mfloat-abi=soft -meabi=4
* gcc -dumpmachine: arm-unknown-linux-gnueabi
* objdump -x for compiled binary:

private flags = 4000002: [Version4 EABI] [has entry point]

* "file" on compiled binary (under Debian):

ELF 32-bit LSB executable, ARM, version 1 (SYSV), for GNU/Linux 2.4.17, dynamically linked (uses shared libs), for GNU/Linux 2.4.17, stripped

* "readelf -h | grep Flags""

Flags: 0x4000002, has entry point, Version4 EABI


[参考]
1ABI/EABI/OABI
http://blog.csdn.net/hongjiujing/archive/2008/07/21/2686556.aspx
2Why ARM's EABI Matters
http://www.chineselinuxuniversity.net/articles/1255.shtml
3.[PDF] The new arm ABI (EABI) and Debian armel port
下载此文件 (29 个页面)
4ArmEabiPort http://wiki.debian.org/ArmEabiPort

感谢文章作者crifan~~~~~~

4OABIEABI兼容性

又搜了许多资料,绝大多数是说如何支持EABI的。关于兼容OABI的文章少之又少!

历尽千辛万苦,终于找到了一篇比较合适的文章,链接如下:

http://blog.163.com/orange_fang/blog/static/18907478201061105345483/ 

内容如下:

======================================================================

OABI和EABI兼容问题  

2010-07-01 11:28:32|  分类: Linux系统管理 |  标签: |字号大中小 订阅

参考:

http://www.unixresources.net/linux/clf/linuxK/archive/00/00/67/92/679297.html

http://www.neixiang.org/shinel/blog/index.php?entry=entry090625-112922

【问题】

常见遇到的一些问题,我所知道的是,对于OABI的交叉编译器,比如arm-linux-gcc这一套工具,如果你当初是用oabi编译的,那么生成的整套工具链,也是oabi的,用oabi的工具链去编译和链接其他eabi的库,就会出问题,常常是在ld的时候,提示类似如下错误:

/usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/../../../../arm-none-linux-gnueabi/bin/ld: failed to merge target specific data of file *.a(POSSet.o)
/usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/../../../../arm-none-linux-gnueabi/bin/ld: ERROR: Source object *.a(SpecialSymbol.o) has EABI version 0, but target asr_IPC has EABI version 5
/usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/../../../../arm-none-linux-gnueabi/bin/ld: failed to merge target specific data of file *.a(SpecialSymbol.o)
collect2: ld returned 1 exit status
make: *** [asr_IPC] 错误 1

【解决办法】

1、用同一套去编译不同的文件和链接不同的库,比如都是用OABI或者都是用EABI,比如重新去编译一个EABI的交叉工具链,然后用这个EABI的工具链去编译你其他的文件。(这个办法对于不能改动的库文件不适用)

2、现在看两个宏,一个是CONFIG_OABI_COMPAT ,意思是说和old ABI兼容;另一个是CONFIG_AEABI ,意思是说指定现在的方式为EABI

1CONFIG_OABI_COMPAT

General informations

The Linux kernel configuration item
CONFIG_OABI_COMPAT:
prompt: Allow old ABI binaries to run with this kernel (EXPERIMENTAL)
type: tristate
depends on:
CONFIG_AEABI && CONFIG_EXPERIMENTAL
defined in arch/arm/Kconfig
found in Linux Kernels: from 2.6.16 release still available on 2.6.34 release
Help text

This option preserves the old syscall interface along with the new (ARM EABI) one. It also provides a compatibility layer to intercept syscalls that have structure arguments which layout in memory differs between the legacy ABI and the new ARM EABI (only for non "thumb" binaries). This option adds a tiny overhead to all syscalls and produces a slightly larger kernel. If you know you'll be using only pure EABI user space then you can say N here. If this option is not selected and you attempt to execute a legacy ABI binary then the result will be UNPREDICTABLE (in fact it can be predicted that it won't work at all). If in doubt say Y.

Hardware
LKDDb

Raw data from LKDDb:
(none)
Sources
Linux Kernel 
Linux Kernel Driver DataBase (LKDDb)
Notes

Pages under construction, so use with care!

These pages are automatic generated. Sources can be found in ...
2CONFIG_AEABI

General informations

The Linux kernel configuration item
CONFIG_AEABI:
prompt: Use the ARM EABI to compile the kernel
type: tristate
depends on:
(none)
defined in arch/arm/Kconfig
found in Linux Kernels: from 2.6.16 release still available on 2.6.34 release
Help text

This option allows for the kernel to be compiled using the latest ARM ABI (aka EABI). This is only useful if you are using a user space environment that is also compiled with EABI.

Since there are major incompatibilities between the legacy ABI and EABI, especially with regard to structure member alignment, this option also changes the kernel syscall calling convention to disambiguate both ABIs and allow for backward compatibility support (selected with CONFIG_OABI_COMPAT).

To use this you need GCC version 4.0.0 or later.
Hardware
LKDDb

Raw data from LKDDb:
(none)
Sources
Linux Kernel 
Linux Kernel Driver DataBase (LKDDb)
Notes

Pages under construction, so use with care!

These pages are automatic generated. Sources can be found in ...

3)内核处理

sys_call_table 在内核中是个跳转表,这个表中存储的是一系列的函数指针,这些指针就是系统调用函数的指针,如(sys_open)。系统调用是根据一个调用号(通常就是表的索引)找到实际该调用内核哪个函数,然后运行该函数完成的。对于old ABI,内核给出的处理是给它建立一个单独的system call table,叫sys_oabi_call_table,这样,兼容方式下就会有两个system call table,以old ABI方式的系统调用会执行old_syscall_table表中的系统调用函数,EABI方式的系统调用会用sys_call_table中的函数指针。

配置无外乎以下4

第一 两个宏都配置行为就是上面说的那样

第二 只配置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 完成函数调用

参考代码:

.align 5
ENTRY(vector_swi)
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0 - r12
add r8, sp, #S_PC
stmdb r8, {sp, lr}^ @ Calling sp, lr
mrs r8, spsr @ called from non-FIQ mode, so ok.
str lr, [sp, #S_PC] @ Save calling PC
str r8, [sp, #S_PSR] @ Save CPSR
str r0, [sp, #S_OLD_R0] @ Save OLD_R0
zero_fp

/*
* Get the system call number.
*/

#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

#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

stmdb sp!, {r4, r5} @ push fifth and sixth args
tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls?
bne __sys_trace

cmp scno, #NR_syscalls @ check upper syscall limit
adr lr, ret_fast_syscall @ return address
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine

add r1, sp, #S_OFF
2: mov why, #0 @ no longer a real syscall
cmp scno, #(__ARM_NR_BASE - __NR_SYSCALL_BASE)
eor r0, scno, #__NR_SYSCALL_BASE @ put OS number back
bcs arm_syscall
b sys_ni_syscall @ not private func

/*
* This is the really slow path. We're going to be doing
* context switches, and waiting for our parent to respond.
*/
__sys_trace:
mov r2, scno
add r1, sp, #S_OFF
mov r0, #0 @ trace entry [IP = 0]
bl syscall_trace

adr lr, __sys_trace_return @ return address
mov scno, r0 @ syscall number (possibly new)
add r1, sp, #S_R0 + S_OFF @ pointer to regs
cmp scno, #NR_syscalls @ check upper syscall limit
ldmccia r1, {r0 - r3} @ have to reload r0 - r3
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine

4)英文说明

What is EABI?

GNU EABI is a new application binary interface (ABI) for Linux. It is part of a new family of ABI's from ARM?Ltd. known in the arm-linux community as EABI (or sometimes Embedded ABI).

How do I use EABI?

To use EABI, you'll need:
A linux kernel that supports EABI. All BitsyG5 kernels support EABI. We also have an experimental kernel for several of our other boards that is configured with EABI support enabled. You can boot these kernels from an ATA flash card or on-board flash just as you would our regular kernels.

An EABI root file system based on ADS' new Debian port which is available for download here.
You can install this root on an NFS server or harddrive, just as you would our regular full Debian distribution.
The root file system includes an arm-linux-gnueabi toolchain which you can use to recompile your own source code.

Why switch to EABI?

According to Debian Wiki the new EABI:
Allows mixing softfloat and hardfloat code.

Uses a more efficient syscall convention.

Will be more compatible with future tools.
Furthermore, the GCC default for EABI will be to use softfloat instructions for floating point arithmetic.

Traditionally, GCC used hardfloat FPA [1] instructions in arm-linux software. Unfortunately, most ARM processors lack support for FPA and instead rely on the kernel for floating point emulation (FPE). They do this through illegal instruction faults which are rather inefficient. Emulating floating point instructions using softfloat is significantly faster than the standard NWFPE used in most arm-linux kernels and appreciably faster than the FastFPE we use in our kernels.

Like most root file systems for ARM computers, Debian uses GCC's default for floating point operations. Prior to the introduction of EABI, the only way to use softfloat was to recompile the entire root file system with softfloat enabled. Now, with an EABI root file system, softfloat instructions will be used by default and you'll be able to mix hard and soft float executables.

In the absence of FPA hardware, the switch to softfloat alone will offer appreciable performance improvement. Additionaly, if your system has some non-FPA floating point hardware, you can recompile critical software with the appropriate hardfloat instructions for an even greater improvement in performance and still be able to run it

arm-linux-gcc

感谢文章作者orange_f~~~~~~

5,欢喜

文中提到了两个宏定义:CONFIG_OABI_COMPAT和CONFIG_AEABI 。然后对照关键字查看内核配置文件,找到了如下配置信息:



注意看下边!“Allow old ABI binaries to run with this kernel (EXPERIMENTAL)”天呐!我竟然没有选上!支持OABI才怪!二话不说,立马选上!编译,烧写进mini2440,简直一气呵成啊!O(_)o 哈哈~~~

6,重新陷入困境

重新运行hello程序~~~~~~终于有输出啦!不过~~等会~~输出结果有些怪异!!!如下:


“Illegal instruction”这是神马情况???无语~~~~~

网上搜了资料,大都说这类情况的发生,是对EABI的不支持导致。并且他们的情况是运行高版本编译器编译出的程序报错!明显与我这个不太一样!问题出在哪里呢?

7,最后的努力

无奈之下对照友善提供的源码配置文件,一项一项进行比较试验。当比较到“Floating point emulation--->”时发现问题了:记得我当初配置内核的时候这里面只是这样的:


但是现在的情况却是这样的:


多出来两项!然后对照友善的此项,发现是这样的:


竟然有三项!而且还选择了第一项!不用说,自己跟着选了第一项,欣喜的事情出现了!下面多了第三项!原来第三项是有赖于第一项的选择啊!哈哈

但是一开始是空的呀!怎么出来的呢?难道我记错了?!这个可能性比较小,因为我是刚刚编译的此内核,对其中的选项还是存在一些记忆的。难道是因为在“Kernel Features--->”里选择了“Allow old ABI binaries to run with this kernel (EXPERIMENTAL)”??

遂做试验,将此选项去掉,果然!“Floating point emulation--->”又成空白的了!心大喜!赶忙编译内核,烧写内核,运行程序试验!

8,成功啦

伟大的“hello world!”终于出现了!!!至此,成功运行了低版本arm-linux-gcc 2.95.3编译的程序。

二、方法总结

1,编译内核时,将“Kernel Features--->”里的“Allow old ABI binaries to run with this kernel (EXPERIMENTAL)”选择上。

2,将“Floating point emulation--->”的“NWFPE math emulation”选上!

竟然有三项!而且还选择了第一项!不用说,自己跟着选了第一项,欣喜的事情出现了!下面多了第三项!原来第三项是有赖于第一项的选择啊!哈哈

但是一开始是空的呀!怎么出来的呢?难道我记错了?!这个可能性比较小,因为我是刚刚编译的此内核,对其中的选项还是存在一些记忆的。难道是因为在“Kernel Features--->”里选择了“Allow old ABI binaries to run with this kernel (EXPERIMENTAL)”??

遂做试验,将此选项去掉,果然!“Floating point emulation--->”又成空白的了!心大喜!赶忙编译内核,烧写内核,运行程序试验!

8,成功啦

伟大的“hello world!”终于出现了!!!至此,成功运行了低版本arm-linux-gcc 2.95.3编译的程序。

二、方法总结

1,编译内核时,将“Kernel Features--->”里的“Allow old ABI binaries to run with this kernel (EXPERIMENTAL)”选择上。

2,将“Floating point emulation--->”的“NWFPE math emulation”选上!


展开阅读全文

没有更多推荐了,返回首页