How to (cross-)compile to both ARM hard- and soft-float (softfp) with a single GCC (cross-)compiler? - gcc

I'd like to use a single (cross-)compiler to compile code for different ARM calling conventions: since I always want to use floating point and NEON instructions, I just want to select the hard-float calling convention or the soft-float (softfp) calling convention.
My compiler defaults to hard-float, but it supports both architectures that I need:
$ arm-linux-gnueabihf-gcc -print-multi-lib
.;
arm-linux-gnueabi;#marm#march=armv4t#mfloat-abi=soft
$
When I compile with the default parameters:
$ arm-linux-gnueabihf-g++ -Wall -o hello_world_armhf hello_world.cpp
It succeeds without any errors.
If I compile with the parameters returned by -print-multi-lib:
$ arm-linux-gnueabihf-g++ -marm -march=armv4t -mfloat-abi=soft -Wall -o hello_world hello_world.cpp
It again compiles without error (By the way, how can I test that the resultant code is hard- or soft-float?)
Unfortunately, if I try this:
$ arm-linux-gnueabihf-g++ -march=armv7-a -mthumb-interwork -mfloat-abi=softfp -mfpu=neon -Wall -o hello_world hello_world.cpp
[...]/gcc/bin/../lib/gcc/arm-linux-gnueabihf/4.7.3/../../../../arm-linux-gnueabihf/bin/ld: error: hello_world uses VFP register arguments, /tmp/ccwvfDJo.o does not
[...]/gcc/bin/../lib/gcc/arm-linux-gnueabihf/4.7.3/../../../../arm-linux-gnueabihf/bin/ld: failed to merge target specific data of file /tmp/ccwvfDJo.o
collect2: error: ld returned 1 exit status
$
I've tested some other permutations of the parameters, but it seems that anything other than the combination shown by -print-multi-lib results in an error.
I've read ARM compilation error, VFP registered used by executable, not object file but the problem there was that some parts of the binary were soft- and some were hard-float. I have a single C++ file to compile...
What parameter(s) I miss to be able to compile with -march=armv7-a -mthumb-interwork -mfloat-abi=softfp -mfpu=neon?
How is it possible that the error is about VFP register arguments while I explicitly have -mfloat-abi=softfp in the command line which prohibits VFP register arguments?
Thanks!
For the records, hello_world.cpp contains the following:
#include <iostream>
int main()
{
std::cout << "Hello, world!" << std::endl;
return 0;
}

You need another compiler with corresponding multilib support.
You can check multilib support with next command.
arm-none-eabi-gcc -print-multi-lib
.;
thumb;#mthumb
fpu;#mfloat-abi=hard
armv6-m;#mthumb#march=armv6s-m
armv7-m;#mthumb#march=armv7-m
armv7e-m;#mthumb#march=armv7e-m
armv7-ar/thumb;#mthumb#march=armv7
cortex-m7;#mthumb#mcpu=cortex-m7
armv7e-m/softfp;#mthumb#march=armv7e-m#mfloat-abi=softfp#mfpu=fpv4-sp-d16
armv7e-m/fpu;#mthumb#march=armv7e-m#mfloat-abi=hard#mfpu=fpv4-sp-d16
armv7-ar/thumb/softfp;#mthumb#march=armv7#mfloat-abi=softfp#mfpu=vfpv3-d16
armv7-ar/thumb/fpu;#mthumb#march=armv7#mfloat-abi=hard#mfpu=vfpv3-d16
cortex-m7/softfp/fpv5-sp-d16;#mthumb#mcpu=cortex-m7#mfloat-abi=softfp#mfpu=fpv5-sp-d16
cortex-m7/softfp/fpv5-d16;#mthumb#mcpu=cortex-m7#mfloat-abi=softfp#mfpu=fpv5-d16
cortex-m7/fpu/fpv5-sp-d16;#mthumb#mcpu=cortex-m7#mfloat-abi=hard#mfpu=fpv5-sp-d16
cortex-m7/fpu/fpv5-d16;#mthumb#mcpu=cortex-m7#mfloat-abi=hard#mfpu=fpv5-d16
https://stackoverflow.com/questions/37418986/how-to-interpret-the-output-of-gcc-print-multi-lib
How to interpret the output of gcc -print-multi-lib
With this configuration gcc -mfloat-abi=hard not only will build your files using FPU instructions but also link them with corresponding libs, avoiding "X uses VFP register arguments, Y does not" error.
The above-mentioned -print-multi-lib output produced by gcc with this patch and --with-multilib-list=armv6-m,armv7,armv7-m,armv7e-m,armv7-r,armv7-a,cortex-m7 configuration option.
If you are interested in building your own gcc with Cortex-A series multilib support, just use --with-multilib-list=aprofile configuration option for any arm*-*-* target without any patches (at list with gcc-6.2.0).

As per Linaro FAQ if your compiler prints arm-linux-gnueabi;#marm#march=armv4t#mfloat-abi=soft then you can only use -march=armv4t. If you want to use -march=armv7-a you need to build compiler yourself.
Following link could be helpful in building yourself GCC ARM Builds

Related

Getting assember output from GCC/Clang in LTO mode

Normally, one can get GCC's optimized assembler output from a source file using the -S flag in GCC and Clang, as in the following example.
gcc -O3 -S -c -o foo.s foo.c
But suppose I compile all of my source files using -O3 -flto to enable link-time whole-program optimizations and want to see the final compiler-generated optimized assembly for a function, and/or see where/how code gets inlined.
The result of compiling is a bunch of .o files which are really IR files disguised as object files, as expected. In linking an executable or shared library, these are then smushed together, optimized as a whole, and then compiled into the target binary.
But what if I want assembly output from this procedure? That is, the assembly source that results after link-time optimizations, during the compilation of IR to assembly, and before the actual assembly and linkage into the final executable.
I tried simply adding a -S flag to the link step, but that didn't really work.
I know disassembling the executable is possible, even interleaving with source, but sometimes it's nicer to look at actual compiler-generated assembly, especially with -fverbose-asm.
For GCC just add -save-temps to linker command:
$ gcc -flto -save-temps ... *.o -o bin/libsortcheck.so
$ ls -1
...
libsortcheck.so.ltrans0.s
For Clang the situation is more complicated. In case you use GNU ld (default or -fuse-ld=ld) or Gold linker (enabled via -fuse-ld=gold), you need to run with -Wl,-plugin-opt=emit-asm:
$ clang tmp.c -flto -Wl,-plugin-opt=emit-asm -o tmp.s
For newer (11+) versions of LLD linker (enabled via -fuse-ld=lld) you can generate asm with -Wl,--lto-emit-asm.

Position dependent code

I am using a processor that uses sparc v8 architecture. I would like to compile my executable such that each function call is absolute address. Using -fPIC option generate position independent code, is there any reverse of this flag ?
Most of GCC options have both -fxxx and -fno-xxx variants.
You can easily test if this is the case for fPIC. Just compile some simple test:
int main () { printf ("Hello, world!\n"); }
with command line like:
gcc -fPIC test.c -S
and look for PLT-relative call in assembler
call puts#PLT
Now try to cancel this option with its reverse:
gcc -fPIC test.c -S -fno-PIC
You will see, that PLT-relative call has gone, so everything works.

Should OCaml compilation with custom linking work in Windows (via MinGW)?

I want to compile an OCaml program interfacing with C code, using a MinGW-based GCC, and using separate compilation (GCC produces the .o, then ocamlopt produces the final executable).
It's not clear to me if (1) this should work on Windows and, if so, (2) which command-line arguments are necessary.
I'm using Jonathan Protzenko's OCaml on Windows installer to install OCaml 4.02.1 along with a Cygwin shell (note that it uses a native windows OCaml compiler, not a Cygwin-based one). I installed gcc using Nuwen's MinGW (but had the same issue when using Strawberry Perl's gcc).
Here's my source code:
C file (tc.c):
#include <stdio.h>
#include "caml/mlvalues.h"
value print(value unused) {
printf("hello from C\n");
return Val_unit;
}
OCaml file (t.ml):
external print : unit -> unit = "print"
let () =
Printf.printf "platform: %s\n" (Sys.os_type);
print ();
The following works just fine:
and#win7 $ ocamlopt t.ml tc.c -o t.exe
and#win7 $ ./t.exe
platform: Win32
hello from C
However, if I use a .o instead of a .c, it doesn't work:
and#win7 $ gcc tc.c -c -I c:/OCaml/lib -o tc.o
and#win7 $ ocamlopt t.ml tc.o -o t.exe
** Cannot resolve symbols for tc.o:
puts
** Fatal error: Unsupported relocation kind 0004 for puts in tc.o
File "caml_startup", line 1:
Error: Error during linking
Both versions work fine on Linux.
I wonder if it's just some silly mistake that I can quickly fix by giving the right arguments to gcc/ocamlc/ocamlopt, or if it's a current limitation of OCaml's native compilation on Windows.
Edit: camlspotter identified the cause, so in retrospect, I did not need Nuwen's MinGW at all. OCaml on Windows already includes a MinGW-based C compiler, except that it is called i686-w64-mingw32-gcc and not gcc.
You are probably using a wrong C compiler or without appropriate options. The best way is to use the same C compiler + options used to build OCaml. You can check it by ocamlc -config:
$ ocamlc -config
version: 4.02.3
standard_library_default: C:/ocamlmgw64/lib
standard_library: C:/ocamlmgw64/lib
standard_runtime: ocamlrun
ccomp_type: cc
bytecomp_c_compiler: x86_64-w64-mingw32-gcc -O -mms-bitfields -Wall -Wno-unused
bytecomp_c_libraries: -lws2_32
native_c_compiler: x86_64-w64-mingw32-gcc -O -mms-bitfields -Wall -Wno-unused
native_c_libraries: -lws2_32
native_pack_linker: x86_64-w64-mingw32-ld -r -o
ranlib: x86_64-w64-mingw32-ranlib
...
For example, the above shows that my OCaml compiler is built over Cygwin 32 bit environment with x86_64-w64-mingw32-gcc. The same applies for the linker and ranlib. Since you can compile C with OCaml code with ocamlopt, the same C compiler must be already installed in your environment.
Building OCaml compiler by yourself to make sure the same C compiler is used both for C and OCaml may be the best way to avoid this sort of C compiler mismatch.

What is the signification of LDFLAGS

I'm trying to compile AODV for ARM linux. I use a SabreLite as a board with kernel version 3.0.35_4.1.0. It's worth mention that i'm using openembedded to create my Linux Distribution for my board.
The AODV source code (http://sourceforge.net/projects/aodvuu/) has a README file which give some indications on how to install it on ARM as stated a bit here.
(http://w3.antd.nist.gov/wctg/aodv_kernel/kaodv_arm.html).
I was able to upgrade the makefile in order to be used with post 2.6 kernel version ( as stated above, i have the 3.0.35_4.1.0 kernel version).
So, basically, what i am trying to do is that i have to create a module (let's say file.ko) and then load it into the ARM (with insmod file.ko command).
To do that, i am using a cross compiler which some values are stated below:
echo $CC :
arm-oe-linux-gnueabi-gcc -march=armv7-a -mthumb-interwork -mfloat-abi=hard -mfpu=neon -mtune=cortex-a9 --sysroot=/usr/local/oecore-x86_64/sysroots/cortexa9hf-vfp-neon-oe-linux-gnueabi
echo $ARCH=arm
echo $CFLAGS: O2 -pipe -g -feliminate-unused-debug-types
echo $LD :
arm-oe-linux-gnueabi-ld --sysroot=/usr/local/oecore-x86_64/sysroots/cortexa9hf-vfp-neon-oe-linux-gnueabi
echo $LDFLAGS :
-Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -Wl,--as-needed
when i launch "make command", i get the following errors:
LD [M] /home/scof/script_emulation/AODV/aodv-uu/lnx/kaodv.o
arm-oe-linux-gnueabi-ld: unrecognized option '-Wl,-O1'
arm-oe-linux-gnueabi-ld: use the --help option for usage information
It states that there is something wrong with the linker. This linker comes from the cross compilation tools and i normally shouldn't touch it.
Anyway, to get this above errors fixed, i try to withdraw the LDFLAGS like this:
export LDFLAGS='',
and after this, the make command works and i get the module kaodv.ko. But when i insert it into my ARM to check, it does not work. It actually freeze my terminal
So my question is, do i have to specify the LDFLAGS when compiling ? Does withdrawing LDFLAGS can have impact on the generated kernel module.
Actually, i try to understand where might be the problem and the only thing that come to me is that may be i should not change manually the LDFLAGS. But if i don't change de LDFLAGS, i get the unrecognized option error.
My second question related to that is, what are the possibly value of LDFLAGS
in ARM compilation
Thanks !!
echo $LDFLAGS : -Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -Wl,--as-needed
There are two common methods of invoking the linker in a GCC-based toolchain. One is to do it directly, but another is to use GCC as a front end to invoke the linker, rather than invoke it directly. When doing this, options intended for the linker are prefixed with -Wl, so that GCC knows to pass them through rather than interpret them itself.
In your case the error message from LD itself
arm-oe-linux-gnueabi-ld: unrecognized option '-Wl,-O1'
Indicates that your build system is passing LDFLAGS directly to the linker, and not by way of GCC.
Therefore, you should remove the -Wl, prefix and your LDFLAGS would instead be
-O1 --hash-style=gnu --as-needed --as-needed
(the duplication of the last argument is probably pointless but benign)
-O1 is an option that tells the linker to optimize. I believe it something new, and your linker may be slightly out of date. Try removing -Wl,-O1, it should still work.

How do I work around the GCC "error: cast from ‘SourceLocation*’ to ‘int’ loses precision" error when compiling cmockery.c?

I need to add unit tests using Cmockery to an existing build environment that uses as hand-crafted Makefile. So I need to figure out how to build cmockery.c (without automake).
When I run:
g++ -DHAVE_CONFIG_H -DPIC -I ../cmockery-0.1.2 -I /usr/include/malloc -c ../cmockery-0.1.2/cmockery.c -o obj/cmockery.o
I get a long list of errors like this:
../cmockery-0.1.2/cmockery.c: In function ‘void initialize_source_location(SourceLocation*)’:
../cmockery-0.1.2/cmockery.c:248: error: cast from ‘SourceLocation*’ to ‘int’ loses precision
Here are lines 247:248 of cmockery.c:
static void initialize_source_location(SourceLocation * const location) {
assert_true(location);
assert_true is defined on line 154 of cmockery.h:
#define assert_true(c) _assert_true((int)(c), #c, __FILE__, __LINE__)
So the problem (as the error states) is GCC doesn't like the cast from ‘SourceLocation*’ to ‘int’.
I can build Cmockery using ./configure and make (on Linux, and on Mac OS X if I export CFLAGS=-I/usr/include/malloc first), without any errors. I've tried looking at the command-line that compiles cmockery.c when I run make (after ./configure):
gcc -DHAVE_CONFIG_H -I. -I. -I./src -I./src -Isrc/google -I/usr/include/malloc -MT libcmockery_la-cmockery.lo -MD -MP -MF .deps/libcmockery_la-cmockery.Tpo -c src/cmockery.c -fno-common -DPIC -o .libs/libcmockery_la-cmockery.o
...but I don't see any options that might work around this error.
In "error: cast from 'void*' to 'int' loses precision", I see I could change (int) in cmockery.h to (intptr_t). And I've confirmed that works. But since I can build Cmockery with ./configure and make, there must be a way to get it to build without modifying the source.
Using gcc instead of g++ on my system turns that error into a warning on my system (Mandriva Linux 2010.1 64-bit) and allows the compilation to complete:
.
.
.
../cmockery-0.1.2/cmockery.c:248: warning: cast from pointer to integer of different size
.
.
.
I feel the need to point out, however, that I am generally wary when I see a whole horde of warnings on what is a relatively common platform (Linux 64-bit/GCC and I would presume others). Using the -m32 option to force compilation to a 32-bit object file does not produce any warnings, so one could presume that the source code used as-is is may not be 64-bit clean. This happens whether you use the autotools or not.
I don't know the project in question, so it might very well be OK, but in any case use with caution...
EDIT:
According to this answer to the OP's question to the cmockery mailing list, the current release is not 64-bit clean at this time. It seems that the errors/warnings were there for a good reason...

Resources