9

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.

Community
  • 1
  • 1
Venemo
  • 18,515
  • 13
  • 84
  • 125
  • Generally, static `.a` libraries are some sort or archive (like *tar*) with a bunch of `.o` objects which may/may not be elf (brief research show ewarm is EABI Elf). You can extract the `.o` files and link one by one. It looks like one will have a `CSTACK$$Limit` and `__iar_program_start`. The 2nd is probably just `_start` with GNU tools. You have to research the symbols or if you can supplement the problem `.o` you will avoid these symbols. You can try the GNU `ar` program to see if it understands the static `.a`; `ld` is groking it. You can also use `nm`, `objdump`, etc. – artless noise Feb 24 '16 at 18:36
  • Generally, it's possible. You seem to be linking the startup code, however, which is almost always tied to the tool chain through linker generated symbols or runtime library callouts, which are all vendor specific. Try removing the startup_chipname.o object from the .a and see if it works better? – Russ Schultz Feb 24 '16 at 19:05
  • @RussSchultz I added more details to the question. No, I'm not linking the startup code but it seems that there are a bunch of symbols in the static file which collide with symbols from the startup file, I also added more info on this to the question. – Venemo Feb 24 '16 at 19:44
  • 1
    @artlessnoise Thanks for the tip, `ar` works! :) I updated the question with my progress. – Venemo Feb 24 '16 at 20:00
  • [this other stackoverflow question](http://stackoverflow.com/questions/19249426/are-static-c-libraries-created-with-one-compiler-compatible-with-another) has an accepted answer that is not correct for all versions of `ewarm` (IAR tools). Why not use `-fno-short-enums` and `-fshort-wchar` which don't complain? Most ARM values are passed in registers, so short enum won't matter unless they are in memory structures passed around. An API of the library is probably needed to answer any questions and I don't think you want to give that. Probably you can write an answer to the original question? – artless noise Feb 25 '16 at 17:28
  • Your work/effort would be a good technical note for them and would make their product more accessible. It is probably in their benefit to help you, unless there is some business agreement with IAR (now owned by ARM?) or the product is end-of-life for them and they don't want to support it. Certainly they are the best people to answer your questions. I have done a similar thing with a 'GAO' soft modem. There DSP code was OK, but the driver they wrote for Linux was garbage. – artless noise Feb 25 '16 at 17:36
  • @artlessnoise If I use `-fno-short-enums` and `-fshort-wchar` the problem is that then it becomes incompatible with built-in stuff like `crti.o`, `libgcc.a` and whatnot (and the C library). I figure that as long as I don't use `wchar_t` and only pass enums between their code and mine through function parameters and return values, this should be fine. – Venemo Feb 26 '16 at 10:26
  • @artlessnoise As to your other comment, yes I agree that it would be in their best interest to help, and they are helpful, but their software guys didn't even manage to get as far as I did now (they just said it is impossible to use this with GCC and that was that). It is sometimes unsettling to see how bad hardware companies are with software. – Venemo Feb 26 '16 at 10:28
  • You don't have to use compiler options globally; so you can wrap there API with `enum` conversions, if that is a concern. Also, you can recompile GCC with `-fno-short-enums` and `-fshort-wchar` using *crosstool-ng* to make an ARM cross. This will give you a library infrastructure that is compatible. – artless noise Feb 26 '16 at 14:08
  • @artlessnoise Unfortunately I encountered a deeper linker issue which I can't seem to get over... so after all it isn't as simple as it seems. – Venemo Mar 02 '16 at 16:13
  • You can alias them to whatever gcc provides. The '__aeabi_foo4' type functions just mean a pointer is aligned. You can use the regular 'foo' (memset, memclr, etc). Using your our own linker script is probably a good idea; a convenient place to alias. Also extract 'evil_sw_stack.a' to '.o' files and use 'nm' on them to find these externals. – artless noise Mar 03 '16 at 13:59
  • @artlessnoise I did that, but I dunno what to do about `__iar_vla_alloc2` and `__iar_vla_dealloc2`. – Venemo Mar 04 '16 at 09:45

0 Answers0