C: Compiling pre-compiled code as inline - c

For some rather complicated reason, I have a set of files which I would like to compile seperatly and then link, but so that the functions in one are placed inline in the second. This is because I would like them to be compiled with different flags in GCC. I know I could fix the problem by looking into how I could get around that, but I would like to know if this is possible.
EDIT 1:
If not, is it possible to compile the 'external' functions into a form of assembly that I could include in the other file. Yes crazy but also cool...
Having a quick look, this could well be an option. I guess it would be impossible to automatically compile it in, so could someone please give me a bit of information about assembly? I've only used basic ARM assembly. I've compiled to toy functions with the -S flag in GCC. How do I link registers with variables? Will they always be in the same order? The function will be highly optimised. When should I start and end the extract? Should I include .cfi_startproc at the start and .cfi_def_cfa 7, 8 at the end?#
EDIT 2:
This post details how gcc can do link-time optimisations like this with -flto. Sadly this is only available with version 4.5, which I do not have nor have the ability to install since I do not have root access of the machine I need to compile this on. Another possible solution would be to explain how I could install a different version of GCC into a folder on a unix machine.

As far as I know gcc doesn't do linktime optimizations (inlining in particular), at least with the standard ld linker (it could be that the new gold linker does it, but I really don't think so). Clang in principle should be capable of doing it, since it depends on LLVM, which supports link time optimizations (it seems that your question is gcc spacific, though).
From your question though, it seems you are looking for a a way to merge object files after compilation, not necessarily by inlining their contained functions. This can be done in multiple ways:
Archiving them into a static library with ar: e.g. ar libfoo.a obj1.o obj2.o.
Combining them together into a third relocatable object (ld's --relocatable option). gcc -Wl,--relocatable -o obj3.o obj1.o obj2.o
Putting them into a shared library (beware that this requires compiling the objects with -fPIC) e.g. gcc -shared -o libfoo.so obj1.o obj2.o

You could compile with the -c option to create a set of .o files, or even make a .so file. Then use the sequence you like in the linking phase of gcc.

Related

Is it possible to specify linker options from code?

I wonder if it's possible to specify a linker option from code? Compilers allow #pragma directives to suppress warnings; how far can we extend this?
(I'm considering implicitly linking on Linux systems and using the GCC compiler; you probably could adapt the answer to your OS)
No, it is impossible to specify link options in code, and notice that the linker is working on object files (not on individual functions inside them).
However, your build procedure could extract linker options from the source code. For instance, if you have a directory with many single-source programs (that is, aa.cc C++ source file compiled into aa.bin executable, bb.cc compiled into bb.bin, etc) you might have a Makefile mentioning
%.bin: %.cc
$(CXX) $(CXXFLAGS) $(shell awk /Link:/{print $2} $<) $^ -o $#
and in aa.cc a comment like:
/* the link option is
Link: -lfoo
*/
BTW, you might also have some GCC plugin which registers and handles your specific #pragma; If you use clang instead of gcc you can also have some Clang plugin; that new pragma could add something in a common Sqlite database which is later used at link time.
So you could do sophisticated things, but I would simply suggest to have your own make rules to handle your linking.

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

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.

What is a multiple compilation, how is working and why i should use it?

I am learning C and I just read the term multiple compilation.Till now I had a single file.c and I used the command gcc file.c to compile it and then ./a.out to execute it. But I got confused a little bit. When should I use the multiple compilation instead of the single and which would be the possible reasons that they will lead me to prefer a multiple compilation instead of the single? I searched it and I found some articles but they didn't cover fully my questions. 1 (this is for c++) , 2If i undestood well if I have some files.c in my project eg file1.c, file2.c and then i want to link them, i execute
gcc file1.c
gcc file.c
gcc file1.o file2.o //somehow i have to create the .o files..
Thank you..
Compilation takes time. There's no point in re-compiling C code that hasn't changed. So, for large projects, it makes sense to split the code into multiple files (typically not randomly of course, but into modules of different functionality) and compile them only when needed.
Linking is the process of taking a bunch of object code (what the .o files are called) and turning them into a single program.
There are many steps to compiling.
When you invoke gcc it will create by default an executable file i.e. all steps in one go:
.c -> .i preprocessor
.i -> .s compiler
.s -> .o assembler
*.o -> a.out linker
Generally the first two take up the most time. If you have a large project then recompiling the entire project may take a lot of time when you are developing. So the compiler allows you to stop at a certain point and reuse previous results of files that have not changed:
gcc -E for preprocess only (rarely used)
gcc -S compile, but don't assemble. Useful for debugging or optimising assembly
gcc -c compile, assemble, but don't link. This is the most commonly used one and produces object files. Those contain your assembled functions (object code), but it's not capable of running because not all functions may be present yet, library functions are missing and the executable header has not been linked in.
The final step gcc -o executable *.o will then take all those and link them together to create an executable. Optionally linking libraries into it.
Generally having all functions in one source file will allow the compiler to do the more optimisations (i.e. inlining), but at the cost of compile time.
Have a look at https://cs.senecac.on.ca/~btp200/pages/images/compile_link.png

When making a library on unix, is anything but "ar rcs" necessary?

I have a number of source files I want to agglomerate into a .a file. I make the library with the command
ar rcs libcathat.a thing1.o thing2.o fish.o
I then attempt to link to this library with the same compiler I used to make the .o files (g++):
g++ -L/path/to/cathat -lcathat seuss.o -o seuss
But this produces errors when I try to use functions defined in thing1.cpp (and in theory represented in thing.o) of the form:
/path/seuss.cpp:46: undefined reference to `redFishBlueFish(int, char**)'
Is there something else I need to do to a .a file to make it possible to link to it?
Try moving the linker statements to the end:
g++ seuss.o -o seuss -L/path/to/cathat -lcathat
If that doesn't work, make sure those symbols are actually in the archive:
nm libcathat.a
Usually, you don't need to do anything else on most modern versions of Unix.
On some, mainly older, versions of Unix, it was necessary to use ranlib on a library to add a lookup table that allowed the linker to find symbols quickly. Almost all modern versions of ar do this automatically. Needing ranlib is something of a hangover from the 'bad old days' of 7th Edition UNIX™.
For some reason which I can't now locate, I was building archives on Mac OS X 10.7.4 with ranlib too. I must have had a reason for doing so, but that reason seems to be irrelevant now — archive libraries seem work OK without ranlib on Mac OS X 10.7.4, at least for a single architecture. I did find a change I made in July 2004 that put ranlib back into a make program, but the check-in notes don't say why I made the change. I've updated the rule definition file so it no longer uses ranlib.

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.

Resources