TL; DR:0x400921f4是如何用IEEE 754表示3.1415801?不知何故,这是一个软浮动吗?我错过了什么?是IEEE 754格式的时候用soft,softfp,硬浮点一样吗?
我目前在结识crosstool-NG而建设自己的交叉编译器为树莓派3和树莓派零W.(* 1)
在他们的论坛和维基阅读文档传开后的过程,我知道RPi3和RPi0编译器需要分别针对不同的ARM体系结构ARMv7和ARMv6。然而,两个SoC都有一个浮点单元,所以我想使用硬浮点来匹配Raspberry Pi库的其余部分。
我测试了我的新建的armv6-rpi-linux-gnueabi-gcc 6.4.0,可以在RaspberryPi Tool repository上找到arm-linux-gnueabihf-gcc 4.9.3。我读了如何确定一个可执行文件是否使用硬件fp here。果然,当我编译以下最小的测试用例。
我编译使用gcc -O0 -o main main.c
与两个编译器。在以下内容中:main.rpi为我的工具链,main.hf为预构建的工具链。
#include <stdio.h>
int main(int argc, char** argv) {
printf("Hello, world %0.7f", 3.14158f);
return 0;
}
readelf -A main.rpi
用我新建的ARMv6-RPI-Linux的gnueabi-GCC时不返回Tag_ABI_VFP_args: VFP registers
,但它使用预构建的使用readelf -A main.hf
ARM-Linux的gnueabihf-GCC时一样。但是,这两个可执行文件运行,理应仅支持以下输出硬FP默认raspbian拉伸图片就好了:
Hello, world 3.1415801
一个奇怪的奇异之处在于ldd main.rpi
在RPI本身只是返回not a dynamic executable
而它列出的依赖关系只是罚款为ldd main.hf
。再次,运行并给出预期的输出。 objdump -R
(在RPI运行)返回两个可执行文件是相同的:
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
0002101c R_ARM_GLOB_DAT __gmon_start__
0002100c R_ARM_JUMP_SLOT [email protected]_2.4
00021010 R_ARM_JUMP_SLOT [email protected]_2.4
00021014 R_ARM_JUMP_SLOT __gmon_start__
00021018 R_ARM_JUMP_SLOT [email protected]_2.4
这让我担心,我用soft
或softfp
,而不是hard
浮点。所以,我看着从两个可执行程序反汇编列表,使用objdump -d
(在RPI运行):
main.rpi:
---------
0001045c <main>:
1045c: e92d4800 push {fp, lr}
10460: e28db004 add fp, sp, #4
10464: e24dd008 sub sp, sp, #8
10468: e50b0008 str r0, [fp, #-8]
1046c: e50b100c str r1, [fp, #-12]
10470: e3a02103 mov r2, #-1073741824 ; 0xc0000000
10474: e59f3014 ldr r3, [pc, #20] ; 10490 <main+0x34>
10478: e59f0014 ldr r0, [pc, #20] ; 10494 <main+0x38>
1047c: ebffffa1 bl 10308 <[email protected]>
10480: e3a03000 mov r3, #0
10484: e1a00003 mov r0, r3
10488: e24bd004 sub sp, fp, #4
1048c: e8bd8800 pop {fp, pc}
10490: 400921f4 .word 0x400921f4 <--- float 3.1415801 here
10494: 00010508 .word 0x00010508 <--- pointer to format string
。
main.hf:
--------
000103f8 <main>:
103f8: e92d4800 push {fp, lr}
103fc: e28db004 add fp, sp, #4
10400: e24dd008 sub sp, sp, #8
10404: e50b0008 str r0, [fp, #-8]
10408: e50b100c str r1, [fp, #-12]
1040c: e59f0018 ldr r0, [pc, #24] ; 1042c <main+0x34>
10410: e3a02103 mov r2, #-1073741824 ; 0xc0000000
10414: e59f3014 ldr r3, [pc, #20] ; 10430 <main+0x38>
10418: ebffffa1 bl 102a4 <[email protected]>
1041c: e3a03000 mov r3, #0
10420: e1a00003 mov r0, r3
10424: e24bd004 sub sp, fp, #4
10428: e8bd8800 pop {fp, pc}
1042c: 000104a4 .word 0x000104a4 <--- pointer to format string
10430: 400921f4 .word 0x400921f4 <--- float 3.1415801 here
要我很大的惊喜两种编译器产生的主用最少的差异相同的结果。 (* 2)对我来说,这两者看起来都很难。
我检查了是否有一些技巧,编译器将浮点数放在实际的字符串中,但没有找到。然后,我去了,随便确定0x400921f4确实是我的浮点值3.1415801得到打印。我使用了两个在线工具here和here进行了检查。那时我对浮点数据的理解显然分崩离析了。
所有转换器都告诉我3.1415801应该是0x40490fa6,并且两个可执行文件0x400921f4中的文字都会产生〜2.1426973。两种编译器都使用特殊(软件?)浮点格式,即使它们表示使用Tag_ABI_FP_number_model: IEEE 754
?我一直认为软件浮点数只是常规的IEEE 754,但是用软件计算,而不是采用不同的格式。
如果我成功地使用了hardfp,并且我的推理已关闭,或者在反汇编中甚至没有看到正确的浮点常量时如何解释显然正确的行为,我就非常困惑。
(* 1)由于这是第一次我使用的crosstool-NG,我用他们的示例配置armv6-rpi-linux-gnueabi
,但降级GCC至6.4.0和gdb到7.12.1至约交叉匹配编译器工具链可用于Windows。我也瞄准内核4.4.83而不是3.12.74。 (* 2)我检查了printf @ plt中是否隐藏了软浮动操作,但事实并非如此。对于两个组件(具有不同的地址):
00010308 <[email protected]>:
10308: e28fc600 add ip, pc, #0, 12
1030c: e28cca10 add ip, ip, #16, 20 ; 0x10000
10310: e5bcfcfc ldr pc, [ip, #3324]! ; 0xcfc
虽然没有必要,但我还没有看到编译器在硬和软浮点之间来回切换时使用不同的格式。但也许这些编译器在那里。 –
嗯......尽管有答案,但是'0x400921F4'的ISTM是构成8字节双“3.1415801”(十六进制值:“0x400921F4BF5A1D83”)的十六进制表示形式的**部分**。 '3.1415801f'的4字节浮点值是'0x40490FA6'。 –