很多讲ARM Linux内核编译的文章或手册都会说
由于arm没有浮点协处理器,所以需要一个模拟浮点机制,
在配置内核时一定要选择一个浮点模拟器NWFPE,如下
--- At least one math emulation must be selected │ │
│ │ <*> NWFPE math emulation │ │
│ │ [ ] Support extended precision │ │
│ │ < > FastFPE math emulation (EXPERIMENTAL)
如果没有浮点模拟器,就会出现错误。比如未定义的指令:
init (1): undefined instruction: pc=4004b020
Code: e3a01000 00000000 00000000 00000000 (eca0420c)
实际上,即使使用了NWFPE,系统的浮点问题也并没有完全解决
NWFPE模拟浮点是利用了undefined instrction handler
即每次浮点指令操作,都会发生一次未定义指令异常(exception),
在这个异常的handler里面,用软件的方法仿真一个浮点指令
如果软件里的浮点运算比较多,那岂不是不停的请求CPU执行undefined instruction,然后产生异常?
答对了,内核模拟浮点指令事实上就是这么回事
这么做带来的后果是带来极频繁的exception,大大增加中断延迟
换句话说,降低系统实时性
另外,每发生一次浮点操作,都要陷入到exception,不难想见会带来极大的性能开销。
内核模拟浮点指令,要实现一个大的case switch
通常情况这个分支预测都会不命中,既要多浪费cpu clock
还会排空BTB,进一步降低后面分支预测命中率
怎么办?——使用软浮点!(MPFR)
软浮点支持是由交叉工具链提供的功能,与Linux内核无关
当使用软浮点工具链编译浮点操作时,编译器会用内联的浮点库替换掉浮点操作
使得生成的机器码完全不含浮点指令,但是又能够完成正确的浮点操作
由于是在编译时优化,这种方式能够让CPU即使作浮点运算时也能够执行连续的指令,减少程序分支
使用软浮点工具链编译产生的浮点操作速度较快
比NWFPE模拟快一个数量级
我们怎么知道交叉工具链是否支持软浮点呢?
很简单,使用编译命令时加上-msoft-float这个CFLAGS就可以了,比如
arm-linux-gcc test。c -msoft-float -o test
如果工具链支持软浮点,那么就可以生成可执行文件
如出错,对不起,该工具链不支持
另一个鉴定的方法,拿到一个编译产生的文件,使用
arm-linux-readelf -e test
可以打印出elf文件头信息
在里面看到software FP就是软浮点格式,否则不是
Flags: 0x202, has entry point, GNU EABI, software FP
ZIX开发环境附带的工具链完善支持软浮点
下面是一个完整的支持软浮点的头部例子
使用arm-linux-readelf -e test输出
ELF Header:
Magic: 7f 45 4c 46 01 01 01 61 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: ARM
ABI Version: 0
Type: EXEC (Executable file)
Machine: ARM
Version: 0x1
Entry point address: 0x839c
Start of program headers: 52 (bytes into file)
Start of section headers: 3432 (bytes into file)
Flags: 0x202, has entry point, GNU EABI, software FP
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 6
Size of section headers: 40 (bytes)
Number of section headers: 31
Section header string table index: 28
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] 。interp PROGBITS 000080f4 0000f4 000013 00 A 0 0 1
[ 2] 。note。ABI-tag NOTE 00008108 000108 000020 00 A 0 0 4
[ 3] 。hash HASH 00008128 000128 000040 04 A 4 0 4
[ 4] 。dynsym DYNSYM 00008168 000168 0000b0 10 A 5 1 4
[ 5] 。dynstr STRTAB 00008218 000218 0000ae 00 A 0 0 1
[ 6] 。gnu。version VERSYM 000082c6 0002c6 000016 02 A 4 0 2
[ 7] 。gnu。version_r VERNEED 000082dc 0002dc 000020 00 A 5 1 4
[ 8] 。rel。dyn REL 000082fc 0002fc 000028 08 A 4 0 4
[ 9] 。rel。plt REL 00008324 000324 000020 08 A 4 11 4
[10] 。init PROGBITS 00008344 000344 000014 00 AX 0 0 4
[11] 。plt PROGBITS 00008358 000358 000044 04 AX 0 0 4
[12] 。text PROGBITS 0000839c 00039c 000260 00 AX 0 0 4
[13] 。fini PROGBITS 000085fc 0005fc 00000c 00 AX 0 0 4
[14] 。rodata PROGBITS 00008608 000608 000010 00 A 0 0 4
[15] 。eh_frame PROGBITS 00008618 000618 000004 00 A 0 0 4
[16] 。ctors PROGBITS 0001061c 00061c 000008 00 WA 0 0 4
[17] 。dtors PROGBITS 00010624 000624 000008 00 WA 0 0 4
[18] 。jcr PROGBITS 0001062c 00062c 000004 00 WA 0 0 4
[19] 。dynamic DYNAMIC 00010630 000630 0000c8 08 WA 5 0 4
[20] 。got PROGBITS 000106f8 0006f8 000030 04 WA 0 0 4
[21] 。data PROGBITS 00010728 000728 00000c 00 WA 0 0 4
[22] 。bss NOBITS 00010734 000734 000004 00 WA 0 0 1
[23] 。comment PROGBITS 00000000 000734 0001d5 00 0 0 1
[24] 。debug_aranges PROGBITS 00000000 000910 000058 00 0 0 8
[25] 。debug_info PROGBITS 00000000 000968 00019a 00 0 0 1
[26] 。debug_abbrev PROGBITS 00000000 000b02 000020 00 0 0 1
[27] 。debug_line PROGBITS 00000000 000b22 000141 00 0 0 1
[28] 。shstrtab STRTAB 00000000 000c63 000103 00 0 0 1
[29] 。symtab SYMTAB 00000000 001240 000780 10 30 92 4
[30] 。strtab STRTAB 00000000 0019c0 00036c 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x00008034 0x00008034 0x000c0 0x000c0 R E 0x4
INTERP 0x0000f4 0x000080f4 0x000080f4 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux。so。2]
LOAD 0x000000 0x00008000 0x00008000 0x0061c 0x0061c R E 0x8000
LOAD 0x00061c 0x0001061c 0x0001061c 0x00118 0x0011c RW 0x8000
DYNAMIC 0x000630 0x00010630 0x00010630 0x000c8 0x000c8 RW 0x4
NOTE 0x000108 0x00008108 0x00008108 0x00020 0x00020 R 0x4
Section to Segment mapping:
Segment Sections。。。
00
01 。interp
02 。interp 。note。ABI-tag 。hash 。dynsym 。dynstr 。gnu。version 。gnu。version_r 。rel。dyn 。rel。plt 。init 。plt 。text 。fini 。rodata 。eh_frame
03 。ctors 。dtors 。jcr 。dynamic 。got 。data 。bss
04 。dynamic
05 。note。ABI-tag