richfelker / musl-cross-make

Simple makefile-based build for musl cross compiler
MIT License
1.29k stars 266 forks source link

How to build compiler without x87 fpu? #76

Open ant6n opened 5 years ago

ant6n commented 5 years ago

Hi, This is a great project, I found it the easiest one to create cross-compilers for many architectures quickly and easily. I'm interested in creating a cross-compiler for the 486 or 386 without FPU (e.g. 486SX). I created a cross-compiler for i386, but it still emits floating point instructions. It tried compiling with i386-linux-musl-gcc -msoft-float -mno-fp-ret-in-387 -static ./hello.c, but then the linker complained about missing float functions (hello.c:(.text+0x34): undefined reference to '__subdf3'). Is there way to build a cross-compiler with the soft-float support built-in (ideally as a default)?

richfelker commented 5 years ago

Most fundamentally, this is a non-starter without musl supporting an i386-softfloat ABI. The normal i386 ABI uses an x87 register for floating point returns, so there's no way to do support for machines without the fpu without either a different ABI or kernel emulation of at least the register.

It looks like you've found the GCC options to change the ABI, but you can't just switch these on an existing toolchain because you can't mix libraries with different ABIs. In particular, at least libgcc (also libstdc++ etc. if you intend to use them) has been built for the normal ABI, and so has musl. The gcc target libs probably have support for an alternate ABI for softfloat, but musl doesn't.

If this is really something you need to do, musl support for an i386-softfloat ABI should be raised on the musl list. It would involve understanding the floating point properties of that ABI (does it still have extended precision in ld80 format?) and would require making the math asm conditional, which in turn would be much easier once all the i386 math asm files are converted to inline asm (a longstanding todo item).

If this is just a toy thing to see if you can do it, the answer is probably just "don't".

ant6n commented 5 years ago

Thank you for the reply!

I'm working on an x86_32 emulator, which doesn't have fpu support yet. I would like to be able to compile programs to start non-trivial testing.

I've since figured out that technically I can compile for soft float in principle. I've found a soft-float library providing singles and doubles that works with gcc (it was posted on the gcc mailing list a long time ago, I packed it in a github rep here). It appears one can compile musl itself for soft float by removing the /src/math/i386/*.s functions, as I understand it this will result in falling back to the non-architecture specific portable C versions. Compiling with -mno-fp-ret-in-387 means no returns in float registers, -mlong-double-64 means long doubles become doubles (This in turn requires replacing the <musl_source>/arch/i386/bits/float.h file with one that assumes 64 bit long doubles, e.g. the arm version). We also need -msoft-float and -lsoft-fp -L<dir>/ieeelib when linking. The -lsoft-fp I patched directly into the Makefile for now, since it has to appear last in the call when linking (but it seems only required for the shared library).

Musl appears to compile and I'm getting simple test programs to work.

The problem is libgcc. In my test, the function __fixunssfsi (convert float->int) was pulled in from libgcc, and it uses float functions. I figured perhaps libgcc itself doesn't get compiled with soft-float enabled. So I looked into the compilation log, I'm seeing calls like this, which I believe is compiling libgcc.

/static-benchmarks/musl-cross-make-0.9.8/build/local/i386-linux-musl/obj_gcc/./gcc/xgcc
-B/static-benchmarks/musl-cross-make-0.9.8/build/local/i386-linux-musl/obj_gcc/./gcc/
-B/i386-linux-musl/bin/ -B/i386-linux-musl/lib/ -isystem /i386-linux-musl/include
-isystem /i386-linux-musl/sys-include
--sysroot=/static-benchmarks/musl-cross-make-0.9.8/build/local/i386-linux-musl/obj_sysroot
-g -O2 -O2  -g -O2 -DIN_GCC  -DCROSS_DIRECTORY_STRUCTURE  -W -Wall -Wno-narrowing
-Wwrite-strings -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition
-isystem ./include   -fpic -mlong-double-80 -DUSE_ELF_SYMVER -g -DIN_LIBGCC2
-fbuilding-libgcc -fno-stack-protector   -fpic -mlong-double-80 -DUSE_ELF_SYMVER
-I. -I. -I../.././gcc -I../../../src_gcc/libgcc -I../../../src_gcc/libgcc/.
-I../../../src_gcc/libgcc/../gcc -I../../../src_gcc/libgcc/../include  -DHAVE_CC_TLS 
-DUSE_TLS -o crtfastmath.o -MT crtfastmath.o -MD -MP
-MF crtfastmath.dep -c ../../../src_gcc/libgcc/config/i386/crtfastmath.c

(The --with-long-double-64 GCC Config was ignored as well)

I believe libgcc is part of the "target" compilation, and there's a way to specify configurations. I tried the following musl-cross-make config, but apparently those a parameters didn't get passed when compiling libgcc.

STAT = -static --static
FLAG = -g0 -O2 -fno-align-functions -fno-align-jumps -fno-align-loops -fno-align-labels -mno-fp-ret-in-387 -mlong-double-64
COMMON_CONFIG += CFLAGS="${FLAG}" CXXFLAGS="${FLAG}" FFLAGS="${FLAG}" LDFLAGS="-s ${STAT}"

COMMON_CONFIG += --disable-nls
GCC_CONFIG += --enable-languages=c,c++
GCC_CONFIG += --disable-decimal-float --enable-softfloat --with-long-double-64
GCC_CONFIG += target_configargs="CFLAGS_FOR_TARGET=\"-g0 -O2 -msoft-float -mno-fp-ret-in-387 -msoft-float -mno-fp-ret-in-387\""

MUSL_FLAG = -msoft-float -mno-fp-ret-in-387 ${FLAG}
MUSL_CONFIG += CFLAGS="${MUSL_FLAG}" CXXFLAGS="${MUSL_FLAG}" FFLAGS="${MUSL_FLAG}" LDFLAGS="-s ${STAT}"

Any pointers? Thanks!

richfelker commented 5 years ago

If you're just testing and plan to add the fpu emulation later, I'd just test with programs that don't use floating point, or under a kernel that traps the exception and emulates floating point in software. Hacking up a working soft-float toolchain for a target where it's not really supported is probably more work than that.

At the very least I think you need some configure option to tell GCC that you want a soft-float-targeting toolchain, rather than just adding CFLAGS_FOR_TARGET, in order to get libgcc.a built correctly.

You also need to make sure that FLT_EVAL_METHOD is defined correctly and that float_t and double_t are defined correctly for your hacked musl i386-softfloat arch and that all the limits in float.h are right. If they're wrong, various math things including strtod and printf type functionality will be badly broken.