Can IAR produce a static library that GCC can link to? - arm

There is a vendor whose software I'd like to work with. They have a code base which they can only compile using IAR Embedded Workbench (as far as I know, their code does not compile with GCC). Unfortunately their hardware only works with their software stack, so I don't really have a choice about whether or not I'd like to use it. They distribute this code as a .a static library file (and accompanying headers) compiled for the ARM Cortex-M4 CPU. (They don't want to distribute sources.) For the sake of this discussion, let's call it evil_sw_stack.a.
I'd like to use this piece of code but I don't have an IAR license and have zero expertise with IAR. I'd like to use GCC.
Is there a way to make IAR produce such a static library that GCC can link to? What kind of compiler option would the vendor need to use to produce such a binary?
(I would guess that the ABI of the resulting binary can be somehow specified and set to a setting which statisfies GCC. )
Example usage of GCC
Their default software stack is very GCC-friendly, this specific one is the only one in their offering which isn't. Generally, I can compile a simple piece of example code if I have the following:
startup_(devicename).S: GCC-specific assembly file
system_(devicename).c
(devicename).ld: linker script
Some header files for the specific device
For example, I can compile a simple piece of example like this:
$ arm-none-eabi-gcc helloworld.c startup_(devicename).S system_(devicename).c -T (devicename).ld -o helloworld -D(devicename) -I. -fno-builtin -ffunction-sections -fdata-sections -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mcpu=cortex-m4 -mthumb -mno-sched-prolog -Wl,--start-group -lgcc -lc -lnosys -Wl,--end-group
So far, so good. No warnings, no errors.
How I try to use the static library
For the sake of this discussion, let's call it evil_sw_stack.a.
This is how I attempted to use it:
$ arm-none-eabi-gcc evil_sw_stack.a helloworld.c startup_(devicename).S system_(devicename).c -T (devicename).ld -o helloworld -D(devicename) -I. -fno-builtin -ffunction-sections -fdata-sections -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mcpu=cortex-m4 -mthumb -mno-sched-prolog -Wl,--start-group -lgcc -lc -lnosys -Wl,--end-group
Unfortunately this complains about multiple definitions of a bunch of functions that are defined in system_(devicename).c. Maybe they accidentally compiled that into this library? Or maybe IAR just compiled it this way? Now, if I try to remove system_(devicename).c from the GCC command line and simply link to the .a file, I get these errors:
/usr/lib/gcc/arm-none-eabi/5.2.0/../../../../arm-none-eabi/bin/ld: warning: thelibrary.a(startup_chipname.o) uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
undefined reference to `__iar_program_start'
undefined reference to `CSTACK$$Limit'
undefined reference to `__iar_program_start'
Poking the file with readelf gets me nowhere:
$ readelf -h evil_sw_stack.a
readelf: Error: evil_sw_stack.a: did not find a valid archive header
Interestingly though, this seems to be getting somewhere:
$ arm-none-eabi-ar x evil_sw_stack.a
Now I've got a bunch of object files which do have ELF headers according to readelf, and yup, they did compile a startup file (of another of their devices) into the library... I'm wondering why, but I think this is a mistake.
This also works:
$ arm-none-eabi-objdump -t evil_sw_stack_objfile.o
So now the question is, is it safe to try to compile these object files into my own application using GCC? According to this other SO question, the object file formats are not compatible.
I assume that the startup code is mistakenly compiled into the library. I can delete it:
$ arm-none-eabi-ar d evil_sw_stack.a startup_(otherdevicename).o
$ arm-none-eabi-ar d evil_sw_stack.a system_(otherdevicename).o
Now I get an evil_sw_stack.a which gcc can accept as an input without complaining.
However, there is one thing that still worries me. When I use the object files instead of the static library, I get these warnings:
/usr/lib/gcc/arm-none-eabi/5.2.0/../../../../arm-none-eabi/bin/ld: warning: evil_objfile.o uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
/usr/lib/gcc/arm-none-eabi/5.2.0/../../../../arm-none-eabi/bin/ld: warning: evil_objfile.o uses 32-bit enums yet the output is to use variable-size enums; use of enum values across objects may fail
So it seems that evil_sw_stack.a was compiled with (the IAR equivalents of) -fno-short-enums and -fshort-wchar. GCC doesn't complain about this when I use evil_sw_stack.a at its command line but it does complain when I try to use any object file that I extracted from the library. Should I worry about this?
I don't use wchar_t in my code so I believe that one doesn't matter, but I would like to pass enums between my code and the library.
Update
Even though the linker doesn't complain, it doesn't work when I actually call some functions from the static library. In that case, make sure to put the libraries in the correct order when you call the linker. According to the accepted answer to this question, they need to be in reverse order of dependency. After doing this, it still misses some IAR crap:
undefined reference to `__aeabi_memclr4'
undefined reference to `__aeabi_memclr'
undefined reference to `__aeabi_memmove'
undefined reference to `__aeabi_memset4'
undefined reference to `__aeabi_memset'
undefined reference to `__iar_vla_alloc2'
undefined reference to `__iar_vla_dealloc2'
undefined reference to `__aeabi_memclr4'
I've found out that the __aeabi functions are defined in libgcc but even though I link to libgcc too, the definition in libgcc doesn't seem to be good enough for the function inside evil_sw_stack.a.
EDIT: after some googling around, it seems that arm-none-eabi-gcc doesn't support these specific __aeabi functions. Take a look at this issue.
Anyway, after taking a look at ARM's runtime ABI docs, the missing __aeabi functions can be trivially implemented using their standard C library equivalents. But I'm not quite sure how __iar_vla_alloc2 and __iar_vla_dealloc2 should work and couldn't find any documentation on them online. The only thing I found out is that VLA means "variable length array".
So, it seems that this will never work unless the chip vendor can compile their static library in such a way that it doesn't use these symbols. Is that right?
Disclaimer
I'd prefer not to disclose who the vendor is and not to disclose which product I work with. They are not proud that this thing doesn't work properly and asked me not to. I'm asking this question to help and not to discredit them.

Related

gcc detect duplicate symbols/functions in static libraries

Is there any way we can get gcc to detect a duplicate symbol in static libraries vs the main code (Or another static library ?)
Here's the situation:
main.c erroneously contained a function definition, e.g. with the signature uint foohash(const char*)
foo.c also contains a function definition with the signature uint foohash(const char*)
foo.c and other source files are compiled to a static util library, which the main program links in, i.e. something like:
gcc -o main main.o util.o -L ./libs -lfooutils
So, now main.o and libs/libfooutils.a both contain a foohash function. Presumably the linker found that symbol in main.o and doesn't bother looking for it elsewhere.
Is there any way we can get gcc to detect such a situation ?
Indeed as Simon Richter stated, --whole-archive option can be useful. Try to change your command-line to:
gcc -o main main.o util.o -L ./libs -Wl,--whole-archive -lfooutils -Wl,--no-whole-archive
and you'll see a multiple definition error.
gcc calls the ld program for linking. The relevant ld options are:
--no-define-common
--traditional-format
--warn-common
See the man page for ld. These should be what you need to experiment with to get the warnings sought.
Short answer: no.
GCC does not actually do anything with libraries. It is the task of ld, the linker (called automatically by GCC) to pull in symbols from libraries, and that's really a fairly dumb tool.
The linker has lots of complex jiggery pokery for combining different types of data from different sources, and supporting different file formats, and all the evil little details of binary executables, but in the end, all it really does is look for undefined symbols and find the definitions.
What you can do is a link trace (pass -t to gcc) to see what comes from where. Or else run nm on all the object files and libraries in your system, and write a script to detect duplicates.

Linking with GCC and -lm doesn't define ceil() on Ubuntu

I am currently using GCC to compile and I need to use <math.h>.
The problem is that it won't recognize the library.
I have also tried -lm and nothing.
The function I tried to use was ceil() and I get the following error:
: undefined reference to `ceil'
collect2: ld returned 1 exit status
I am using the latest Ubuntu and math.h is there.
I tried to use -lm on a different computer, and it worked perfectly.
How can I solve this problem?
I did include <math.h>. Also, the command I used was:
gcc -lm -o fb file.c
Take this code and put it in a file ceil.c:
#include <math.h>
#include <stdio.h>
int main(void)
{
printf("%f\n", ceil(1.2));
return 0;
}
Compile it with:
$ gcc -o ceil ceil.c
$ gcc -o ceil ceil.c -lm
One of those two should work. If neither works, show the complete error message for each compilation. Note that -lm appears after the name of the source file (or the object file if you compile the source to object before linking).
Notes:
A modern compiler might well optimize the code to pass 2.0 directly to printf() without calling ceil() at all at runtime, so there'd be no need for the maths library at all.
Rule of Thumb: list object files and source files on the command line before the libraries. This answer shows that in use: the -lm comes after the source file ceil.c. If you're building with make etc, then you typically use ceil.o on the command line (along with other object files); normally, you should list all the object files before any of the libraries.
There are occasionally exceptions to the rule of thumb, but they are rare and would be documented for the particular cases where the exception is expected/required. In the absence of explicit documentation to the contrary, apply the rule of thumb.
I just wanted to mention that Peter van der Linden's book Expert C Programming has a good treatment on this subject in chapter 5 Thinking of Linking.
Archives (static libraries) are acted upon differently than are shared objects (dynamic libraries). With dynamic libraries, all the library symbols go into the virtual address space of the output file, and all the symbols are available to all the other files in the link. In contrast, static linking only looks through the archive for the undefined symbols presently known to the loader at the time the archive is processed.
If you specify the math library (which is usually a static one) before your object files, then the linker won't add any symbols.
Try compiling like that:
gcc -Wall -g file.c -lm -o file
I had the same problem and it was solved using this command. Also if you installed your Ubuntu the same day you had the problem it might be an update problem.

Undefined Symbols when linking against a mixed C and Fortran in OS X 10.6.4

I'm trying to compile a code (not mine) that consists of mixed Fortran and C source files, which are compiled into a library. This library can either be linked against directly, or (more usefully) driven from a python class. I have previously successfully built the code as 32-bit with g77 and gcc, but I've encountered a situation in which the code uses big chunks of memory, and needs to be 64-bit.
I've attempted to build as both 64-bit only, or as a universal binary, with gfortran 4.2.3 (binary dist from the AT&T R project) and the system gcc (4.2). The source files build correctly, but when I attempt to link against the library, I get many "Undefined Symbols" errors for a number of the Fortran functions. An nm on the library shows that the symbols appear to exist, but obviously the linker isn't finding them.
Here are two (of many) of the compile commands (which produce no errors):
/usr/local/bin/gfortran -arch ppc -arch i386 -arch x86_64 -fPIC -fno-strength-reduce -fno-common -ff2c -Wall -c lsame.f
gcc -c -I/Users/keriksen/Research/atomic_data/fac -I/Users/keriksen/Research/atomic_data/fac/faclib -O2 -fPIC -fno-strength-reduce -fno-common pmalloc.c
And the link step, which bombs:
gcc -o sfac sfac.c stoken.c -I/Users/keriksen/Research/atomic_data/fac -I/Users/keriksen/Research/atomic_data/fac/faclib -O2 -fPIC -fno-strength-reduce -fno-common -L/Users/keriksen/Research/atomic_data/fac -lfac -lm -lgfortran -lgcc
A sample Undefined Symbol:
"_acofz1", referenced from:
_HydrogenicDipole in libfac.a(coulomb.o)
_HydrogenicDipole in libfac.a(coulomb.o)
and the corresponding nm that shows that symbol exists:
niobe:atomic_data/fac[14] nm libfac.a | grep acof
0000000000000000 T _acofz1_
0000000000002548 S _acofz1_.eh
U _acofz1
Am I doing something stupid, like not including a necessary switch to the linker, or is something more subtle going on here?
Per Yuji's suggestion:
The cfortran.h header file (available on the Web, and apparently fairly widely used) that handles the C/Fortran compatibility issues does not handle gfortran out of the box. I hacked it (incorrectly) to ignore this fact, and paid for my insolence.
The specific issue is that gfortran emits object code containing symbols with a trailing underscore, gcc does not.
The correct thing to do was to set the environment variable CPPFLAGS to -Df2cFortran. Once this macro is set, cfortran.h adds the necessary underscore to the symbols in the calling C functions' object code, and the linker is happy.
The other surprising thing in this particular instance was the configure script looks at the F77 environment variable for the name of the fortran compiler. Once I set F77 to "/usr/local/bin/gfortran -arch x86_64" the generated Makefile was correct, and it produced 64-bit only object code. I'm not sure if this is standard configure behavior, or if it a peculiarity of this particular script.
The upshot is that I now have a 64-bit shared library which plays nicely with a 64-bit python I downloaded. I'm half-considering going back and trying to produce a universal library that will work with the system python, but I'm not sure I want to tempt fate.

AIX xlC cross-compilation/linkage for C++ not finding C symbols

I am attempting to cross-compile on AIX with the xlc/xlC compilers.
The code compiles successfully when it uses the default settings on another machine. The code actually successfully compiles with the cross-compilation, but the problem comes from the linker. This is the command which links the objects together:
$(CHILD_OS)/usr/vacpp/bin/xlC -q32 -qnolib -brtl -o $(EXECUTABLE) $(OBJECT_FILES)
-L$(CHILD_OS)/usr/lib
-L$(CHILD_OS)/usr/vacpp/lib/profiled
-L$(CHILD_OS)/usr/vacpp/lib
-L$(CHILD_OS)/usr/vac/lib
-L$(CHILD_OS)/usr/lib
-lc -lC -lnsl -lpthread
-F$(CHILD_OS)$(CUSTOM_CONFIG_FILE_LOCATION)
When I attempt to link the code, I get several Undefined symbols:
.setsockopt(int,int,int,const void*,unsigned long), .socket(int,int,int), .connect(int,const sockaddr*,unsigned long), etc.
I have discovered that the symbols missing are from the standard c library, libc.a. When I looked up the symbols with nm for the libc.a that is being picked up, the symbols do indeed exist. I am guessing that there might be a problem with the C++ being unable to read the C objects, but I am truly shooting in the dark.
Sound like it might be a C++ name mangling problem.
Run nm on the object files to find out the symbols that they are looking for. Then compare the exact names against the libraries.
Then check the compilation commands, to ensure that the right version of the header files is being included - maybe it's including the parent OS's copy by mistake?
I was eventually able to get around this. It looks like I was using the C++ compiler for .c files. Using the xlc compiler instead of the xlC compiler for C files fixed this problem.

Portable way to link statically against one of the libraries

I am creating a utility which depends on libassuan aside other depends. While these ‘others’ provide shared libraries, libassuan comes with static one only.
libassuan comes with simple libassuan-config tool which is meant to provide CFLAGS & LDFLAGS for the compiler/linker to use. These LDFLAGS refer to the library as -lassuan.
The result of standard call of make is then:
cc -I/usr/include/libmirage -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -lmirage -lglib-2.0 -L/usr/lib64 -lassuan -o mirage2iso mirage2iso.c mirage-getopt.o mirage-wrapper.o mirage-password.o
mirage-password.o: In function `mirage_input_password':
mirage-password.c:(.text+0x1f): undefined reference to `assuan_pipe_connect'
mirage-password.c:(.text+0x32): undefined reference to `assuan_strerror'
collect2: ld returned 1 exit status
make: *** [mirage2iso] Error 1
(I've just started writing this unit and that's why there aren't more errors)
So, if I understand the result correctly, gcc doesn't want to link the app to libassuan.a.
Using -static here will cause gcc to prefer static libraries over shared which is unindented. I've seen solution suggesting using something like that:
-Wl,-Bstatic -lassuan -Wl,-Bdynamic
but I don't think it would be a portable one.
I think the best solution would be to provide full path to the static library file but libassuan-config doesn't provide much of help (all I can get from it is -L/usr/lib64 -lassuan).
Maybe I should just try to create the static library path by ‘parsing’ returned LDFLAGS and using -L for the directory name and -l for the library name — and then hoping that in all cases libassuan-config will return it like that.
What do you think about that? Is there any good, simple and portable solution to resolve the issue?
PS. Please note that although I'm referring to gcc here, I would like to use something that will work fine with other compilers.
PS2. One additional question: if package does install static library only, returning such LDFLAGS instead of full .la path can be considered as a bug?
gcc will link to libassuan.a if it doesn't find libassuan.so
It's probably the order symbols are looked up in the static library when you link. The order matters.
)
Assuming gcc can find libassuan.a and it actually provides the functions the linker complains about, try:
cc -I/usr/include/libmirage -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -lmirage -lglib-2.0 -L/usr/lib64 -o mirage2iso mirage2iso.c mirage-getopt.o mirage-wrapper.o mirage-password.o -lassuan
Since you say libassuan is under /usr/lib64 it's probably a 64 bit library, are your app and the other libraries 64 bit as well ?
Compiler's command-line options are not a portable thing. There's no standard for it. Every compiler uses its own and several can merely informally agree to comply with each other in command-line format. The most portable way for your linking is to use libassuan-config, of course. I think, it can generate not only flags for gcc, but for other compilers as well. If it can't, then no portable way exists, I suppose (other than CMake or something on higher level).
The command line to cc you shown is totally correct. If you have a static library libassuan.la and path to it is supplied to -L option, then the compiler does link against it. You can see it from its output: has it not found the static library, would it complain with error message like "can't find -lassuan". I
Moreover, if no libassuan.so is found, then compiler links against your library statically, even if you haven't used -Wl,-Bstatic stuff or -static flag.
Your problem may be in persistence of several versions of libassuan in your system. Other that that, I don't see any errors in what you've provided.
Which directory is libassuan.a in
I think the first error is not gcc doesn't want to link the app to libassuan.a it is more gcc does not know where libassuan.a . You need to pass gcc a -L parameter giving the path to libassuan.a .
e.g.
-L /home/path

Resources