Cross compiling - Error: selected processor does not support `fmrx r3,fpexc' in ARM mode - Beaglebone - gcc

I'm trying to cross-compile a file to flash into the Beaglebone Black.
All works fine, but if I try to enable the FPU with
#define set_en_bit_in_fpexc() do { \
int dummy; \
__asm__ __volatile__ ("fmrx %0,fpexc\n\t" \
"orr %0,%0,#0x40000000\n\t" \
"fmxr fpexc,%0" : "=r" (dummy) : :); \
} while (0)
I get the following error
Error: selected processor does not support `fmrx r3,fpexc' in ARM mode
Error: selected processor does not support `fmxr fpexc,r3' in ARM mode
I also tried with thumb mode, but I get the same errors.
Of course if I remove the part of the code that initialize the FPU it works fine.
Why I get those errors?
Makefile
[...]
CROSSPATH?=/usr/bin
CROSSPFX=$(CROSSPATH)/arm-none-eabi-
CC=$(CROSSPFX)gcc
AS=$(CROSSPFX)as
LD=$(CROSSPFX)ld
NM=$(CROSSPFX)nm
OBJCOPY=$(CROSSPFX)objcopy
OBJDUMP=$(CROSSPFX)objdump
CFLAGS=-Wall -Wextra -O2 -ffreestanding
ARCHFLAGS=-mcpu=cortex-a8 -march=armv7-a -mfpu=neon
CCARCHFLAGS=$(ARCHFLAGS) -marm
[...]
I'm on Arch, kernel 4.8.1
P.S. My professor uses the linaro cross-compiler and it works just fine

Most of the Linaro toolchains are configured for ARMv7 hard-float by default (certainly the Linux ones, I'm less sure about the bare-metal ones). Looking at the configuration of the arm-none-eabi toolchain as packaged by Arch, I surmise it's just using the GCC defaults for things like that, which implies something like ARMv4t, and crucially, soft-float ABI.
Whilst the -mfpu option controls code generation in terms of which floating-point instructions may be used, apparently it's the float ABI which controls whether it'll let you do things which really only make sense on a hardware FPU, rather than under floating-point emulation.
When it's not configured by default, you need to explicitly select a floating-point ABI implying an actual hardware FPU, i.e. -mfloat-abi=hard (or -mfloat-abi=softfp, but there's really no reason to use that unless you need to link against other soft-float code).

-mfpu=vfpv3-d16 -mfloat-abi=hard
Just to give a more direct solution, I had to add -mfpu=vfpv3-d16.
Test code a.S:
fmrx r2, fpscr
Working command:
sudo apt-get install binutils-arm-linux-gnueabihf
arm-linux-gnueabihf-as -mfpu=vfpv3-d16 -mfloat-abi=hard a.S
Note that -mfloat-abi=hard is enabled by default on this particular build of arm-linux-gnueabihf-as, and could be omitted.
The default value of float-abi likely depends on -msoft-float vs -mhard-float controlled at GCC build time with:
./configure --with-float=soft
as documented at: https://gcc.gnu.org/install/configure.html You can get the flags used for your toolchain build with gcc -v as mentioned at: What configure options were used when building gcc / libstdc++? I could not however easily determine its default value if not given.
You may also be interested in -mfloat-abi=softfp which can produce hard floats for the executable, but generate soft function calls: ARM compilation error, VFP registered used by executable, not object file
The possible values of -mfpu= can be found at: https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/ARM-Options.html#ARM-Options
Also note that FMRX is the pre-UAL syntax for VMRS which the newer recommended syntax, see also: Are ARM instructuons SWI and SVC exactly same thing?
Tested on Ubuntu 16.04, arm-linux-gnueabihf-as 2.26.1.

Related

What is the correct way to enable soft floating point computation for 68000 with gcc and newlib?

I am using crosstool-ng to crosscompile for 68000 (version:crosstool-ng-1.24.0-rc2, host OS:Ubuntu 20.04)
My target is a 68000 (plain, not a 68020 or a cpu with floating point support).
I am compiling using a test program which multiplies two floats, using
-m68000 -mcpu=68000 -msoft-float -Wall -fno-builtin -O2
However, when I execute it, I get illegal instruction error
(notice, this happens only if I use floats)
Suspecting newlib is targeting 68020, I tried adding
CT_LIBC_NEWLIB_TARGET_CFLAGS="-m68000 -msoft-float"
but that made no difference.
What am I doing wrong? Do I need some code in the illegal instruction handler?

Link a "toy" OS using llvm/clang

Is it possible (within reason) to build a "toy" OS on a mac using llmv/clang (and the other "normal" build tools)? By "toy" OS, I mean the simple, "Hello, World" examples found on OSDev (http://wiki.osdev.org/Bare_Bones) and x86 Bare Metal (https://github.com/cirosantilli/x86-bare-metal-examples).
My main problem is I can't figure out how to specify precisely where the linker should place the code (i.e., that the starting point should be 0x7c00, that bytes 510 and 511 need to be 0xaa55, etc.).
I would say yes it is possible within reason, at least if you consider waiting for a build of lld (and its dependency llvm) reasonable. Instructions to build lld can be found on their website or as part of this answer.
Compiling and linking for a different target than the host is relatively easy with clang. You just have to set a target, for example -target i386-none-elf for an ELF binary. Cross-compilation using clang is explained in more detail here.
As for macOS, as Micheal Petch noted, you have to use another linker than the standard ld installed. You could in theory install binutils to get an ELF ld but then you have to compile it yourself to set the target. My recommendation is to use lld which can target many architectures without the need to recompile.
With clang and a lld in place we can compile sources with
clang -c -o file.o file.c -target i386-none-elf # freestanding flags omitted
and then link them with
clang -o kernel.bin file.o -target i386-linux-elf -nostdlib -Wl,linkerscript.ld -fuse-ld=lld
Note that for linking I am using i386-linux-elf because there is a bug in clang where they just forward their input to gcc. But when using -nostdlib it is essentially the same.
If you want to see a complete example ready to build, you can take a look at https://github.com/Henje/x86-Toy-OS.

GCC Cortex-M4 -mfpu=vfpv4 vs. -mfpu=fpv4-sp-d16

I'm using a Freescale K22 (Cortex-M4F) with Kinetis Design Studio, which includes a GNU toolchain. I'm trying to use a binary-only library provided by Invensense, and they compiled it with GCC for use on a the Cortex-M4F using the compiler's CPU options "-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=vfpv4"
The Freescale toolchain defaults to "-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16". When I try to link my program with the vendor binary-only library, I get link errors like:
c:/freescale/kds_1.1.1/toolchain/bin/../lib/gcc/arm-none-eabi/4.8.0/../../../../arm-none-eabi/bin/ld.exe: error: ./startup/startup.o uses VFP register arguments, 22F_eval_spi_to_invensense_CHECKED_IN.elf does not
c:/freescale/kds_1.1.1/toolchain/bin/../lib/gcc/arm-none-eabi/4.8.0/../../../../arm-none-eabi/bin/ld.exe: failed to merge target specific data of file ./startup/startup.o
I can rebuild the Kinetis platform library for -mfpu=vfpv4, but I still get the link errors, presumably because other Kinetis libraries are compiled with
"-mfpu=fpv4-sp-d16".
Since both are intended for the Cortex-M4 with FPU, is there any actual difference between GCC generated code for vpfv4 and fpv4-sp-d16? Are they actually incompatible, or is the linker just overly pedantic?

How to generate location independent code using GNU ARM toolchain?

I am using ARM ELF toolchain for my project. I am working on a bootloader which needs to be location independent as it will relocate it self from flash to ram upon reset. I have tried hard to figure out how to compile location independent code using GNU ARM toolchain but can not seem to make it work.
I have tried using -fpic and -fpie options for the compiler and -pie for linker but when I use these options the compiler complains that no section is defined for either .got or .plt sections. I am not sure where these sections should go i.e in BSS or TEXT. After googling about this, I think I should only use -fpie but I am not sure.
Can someone with experience with this please help me. I am using GNU ARM 4.1.1
you can generate Position Independent Code [PIC] by supplying -mapcs-reentrant option to arm-linux-gnueabi-gcc and -Wa,-K option to fellow assembler.
like:
arm-linux-gnueabi-gcc <other option> -mapcs-reentrant -Wa, -K <other option> files..

How to use gcc and -msoft-float on an i386/x86-64? [duplicate]

Is it (easily) possible to use software floating point on i386 linux without incurring the expense of trapping into the kernel on each call? I've tried -msoft-float, but it seems the normal (ubuntu) C libraries don't have a FP library included:
$ gcc -m32 -msoft-float -lm -o test test.c
/tmp/cc8RXn8F.o: In function `main':
test.c:(.text+0x39): undefined reference to `__muldf3'
collect2: ld returned 1 exit status
It is surprising that gcc doesn't support this natively as the code is clearly available in the source within a directory called soft-fp. It's possible to compile that library manually:
$ svn co svn://gcc.gnu.org/svn/gcc/trunk/libgcc/ libgcc
$ cd libgcc/soft-fp/
$ gcc -c -O2 -msoft-float -m32 -I../config/arm/ -I.. *.c
$ ar -crv libsoft-fp.a *.o
There are a few c files which don't compile due to errors but the majority does compile. After copying libsoft-fp.a into the directory with our source files they now compile fine with -msoft-float:
$ gcc -g -m32 -msoft-float test.c -lsoft-fp -L.
A quick inspection using
$ objdump -D --disassembler-options=intel a.out | less
shows that as expected no x87 floating point instructions are called and the code runs considerably slower as well, by a factor of 8 in my example which uses lots of division.
Note: I would've preferred to compile the soft-float library with
$ gcc -c -O2 -msoft-float -m32 -I../config/i386/ -I.. *.c
but that results in loads of error messages like
adddf3.c: In function '__adddf3':
adddf3.c:46: error: unknown register name 'st(1)' in 'asm'
Seems like the i386 version is not well maintained as st(1) points to one of the x87 registers which are obviously not available when using -msoft-float.
Strangely or luckily the arm version compiles fine on an i386 and seems to work just fine.
Unless you want to bootstrap your entire toolchain by hand, you could start with uclibc toolchain (the i386 version, I imagine) -- soft float is (AFAIK) not directly supported for "native" compilation on debian and derivatives, but it can be used via the "embedded" approach of the uclibc toolchain.
GCC does not support this without some extra libraries. From the 386 documentation:
-msoft-float Generate output containing library calls for floating
point. Warning: the requisite
libraries are not part of GCC.
Normally the facilities of the
machine's usual C compiler are used,
but this can't be done directly in
cross-compilation. You must make your
own arrangements to provide suitable
library functions for
cross-compilation.
On machines where a function returns
floating point results in the 80387
register stack, some floating point
opcodes may be emitted even if
-msoft-float is used
Also, you cannot set -mfpmath=unit to "none", it has to be sse, 387 or both.
However, according to this gnu wiki page, there is fp-soft and ieee. There is also SoftFloat.
(For ARM there is -mfloat-abi=softfp, but it does not seem like something similar is available for 386 SX).
It does not seem like tcc supports software floating point numbers either.
Good luck finding a library that works for you.
G'day,
Unless you're targetting a platform that doesn't have inbuilt FP support, I can't think of a reason why you'd want to emulate FP support.
Doesn't your x386 platform have external FPU support? Pity it's not a x486 with the FPU built in!
In my experience, any soft emulation is bound to be much slower than its hardware equivalent.
That's why I finished up writing a package in Ada to taget the onboard 68k FPU instead of using the soft emulation provided by the compiler manufacturer at the time. They finished up bundling it in their compiler as a matter of fact.
Edit: Just seen your comment below. Hmmm, if you don't need a full suite of FP support is it possible to roll your own for the few math functions you do need? That how the Ada package I mentioned got started.
HTH
cheers,

Resources