使用硬浮点 (PowerPC) 时对“__floatundisf”的未定义引用

问题描述

我正在使用硬浮动为 PowerPC 构建代码,突然遇到这个问题。

我知道这个符号属于 gcc 的 soft-float 库。我不明白的是为什么它要尝试使用它,尽管我努力告诉它使用硬浮动。

制作标志:

CFLAGS += -mcpu=750 -mhard-float -ffast-math -fno-math-errno -fsingle-precision-constant -shared -fpic -fno-exceptions -fno-asynchronous-unwind-tables -mrelocatable -fno-builtin -G0 -O3 -I$(GCBASE) -Iinclude -Iinclude/gc -I$(BUILDDIR)
ASFLAGS += -I include -mbroadway -mregnames -mrelocatable --fatal-warnings
LDFLAGS += -nostdlib -mhard-float $(LINKSCRIPTS) -Wl,--nmagic -Wl,--just-symbols=$(GLOBALSYMS)

有问题的代码

static void checkTime() {
    u64 ticks = __OSGetSystemTime();
    //note timestamp here is seconds since 2000-01-01
    float secs = ticks / 81000000.0f; //everything says this should be 162m / 4,//but I only seem to get anything sensible with 162m / 2.
    int days  = secs / 86400.0f; //non-leap days
    int years = secs / 31556908.8f; //approximate average
    int yDay = days % 365;
    debugPrintf("Y %d D %d",years,yDay);
}

我还需要什么来阻止 gcc 尝试使用软浮动?为什么它突然决定这样做?

解决方法

查看 GCC docs__floatundisf 将 unsigned long 转换为浮点数。如果我们使用 -O1 编译您的代码*并运行 objdump,我们可以看到 __floatundisf 确实来自将您的 u64 除以浮点数:

    u64 ticks = __OSGetSystemTime();
  20:   48 00 00 01     bl      20 <checkTime+0x20> # Call __OSGetSystemTime
            20: R_PPC_PLTREL24  __OSGetSystemTime
    //note timestamp here is seconds since 2000-01-01
    float secs = ticks / 81000000.0f; //everything says this should be 162m / 4,24:   48 00 00 01     bl      24 <checkTime+0x24> # Call __floatundisf
            24: R_PPC_PLTREL24  __floatundisf
  28:   81 3e 00 00     lwz     r9,0(r30)
            2a: R_PPC_GOT16 .LC0
  2c:   c0 09 00 00     lfs     f0,0(r9)   # load the constant 1/81000000
  30:   ec 21 00 32     fmuls   f1,f1,f0   # do the multiplication ticks * 1/81000000

所以你得到它用于 u64/浮点计算。

如果您将 u64 转换为 u32,我也会看到它消失了。

为什么会产生?查看 750CL 的手册,我希望它在很大程度上与您的芯片等效,没有指令可以从内存中读取 8 字节整数并将其转换为浮点数。 (看起来也没有将 32 位整数直接转换为浮点数的方法:gcc 而是内联了一系列令人困惑的整数和浮点数操作指令。)

我不知道 __OSGetSystemTime 的单位是什么,但是如果您可以通过丢弃一些较低的位将其减少为 32 位整数,或者通过使用公约数的一些技巧,您可以摆脱调用.

*:稍作修改即可在我的系统上编译。