2017-09-21 45 views
1

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 

这让我担心,我用softsoftfp,而不是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得到打印。我使用了两个在线工具herehere进行了检查。那时我对浮点数据的理解显然分崩离析了。

所有转换器都告诉我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 
+0

虽然没有必要,但我还没有看到编译器在硬和软浮点之间来回切换时使用不同的格式。但也许这些编译器在那里。 –

+0

嗯......尽管有答案,但是'0x400921F4'的ISTM是构成8字节双“3.1415801”(十六进制值:“0x400921F4BF5A1D83”)的十六进制表示形式的**部分**。 '3.1415801f'的4字节浮点值是'0x40490FA6'。 –

回答

4

当浮子被传递给printf()它被提升到两倍,并且编译器具有优化了的转换。 (double)(3.14158f)的表示是0x400921f4c0000000。 MS部分进入r3,r2进入LS部分。另外,因为printf()是可变参数,所以在两种情况下都使用整数寄存器传递FP值(软浮点样式)。

+0

哇!感谢您及时的回复。我想昨天晚上我只是很密集。非常有意义。我会等待一天左右,然后接受! – FRob

0
float fun (float a) 
{ 
    return(a+1.234F); 
} 

与硬浮

00000000 <fun>: 
    0: eddf 7a02 vldr s15, [pc, #8] ; c <fun+0xc> 
    4: ee30 0a27 vadd.f32 s0, s0, s15 
    8: 4770  bx lr 
    a: bf00  nop 
    c: 3f9df3b6 svccc 0x009df3b6 

与软浮子

00000000 <fun>: 
    0: b508  push {r3, lr} 
    2: f24f 31b6 movw r1, #62390 ; 0xf3b6 
    6: f6c3 719d movt r1, #16285 ; 0x3f9d 
    a: f7ff fffe bl 0 <__aeabi_fadd> 
    e: bd08  pop {r3, pc} 

相同的恒定这是正确的常数。

但正如我在得到我的答案之前所指出的那样。除非另有说明,否则C中的浮点数是双精度值,请注意F在常量的末尾,没有编译器必须提升为double才能执行操作(因为这是我通过不放置F,常量被认为是双倍的)然后转换回单一返回。

00000000 <fun>: 
    0: b508  push {r3, lr} 
    2: f7ff fffe bl 0 <__aeabi_f2d> 
    6: a304  add r3, pc, #16 ; (adr r3, 18 <fun+0x18>) 
    8: e9d3 2300 ldrd r2, r3, [r3] 
    c: f7ff fffe bl 0 <__aeabi_dadd> 
    10: f7ff fffe bl 0 <__aeabi_d2f> 
    14: bd08  pop {r3, pc} 
    16: bf00  nop 
    18: c8b43958 ldmgt r4!, {r3, r4, r6, r8, r11, r12, sp} 
    1c: 3ff3be76 svccc 0x00f3be76