FMI - C standard library version differences cause linking errors - linker

I have a publicly-available FMU for which I am trying to link the embedded .so file with the rest of my program. (This is contained within the .fmu file if you view as an archive.) During the linking phase I am getting the following undefined reference errors:
RoomHeating_OM_RH.so: undefined reference to '__longjmp_chk#GLIBC_2.11'
RoomHeating_OM_RH.so: undefined reference to '__fread_chk#GLIBC_2.7'
If I look at the content of RoomHeating_OM_RH.so with a tool like nm -a, I see lots of undefined references of this form that aren't causing errors at link time. Here are a couple such lines from the nm -a output:
U __vsnprintf_chk##GLIBC_2.3.4
U _setjmp##GLIBC_2.0
However, the ones that are causing errors are differentiated from the rest of them by the fact that they have newer versions of GLIBC in the name. Here's what I have in my /lib dir for the libc library (yes I realize these are old versions, but it's what I am stuck with for now):
/lib/libc-2.5.so
/lib/libc.so.6
So my guess is that I don't have a new enough version of libc to link against. Is it a requirement that the version of libc be exactly what the .so file calls out? Or does it only need to be equal to or newer than the version called out? Furthermore, does the FMI specification even cover this aspect of compatibility? Or does it assume that IF .so files are provided in the FMU that they MUST be compiled using the same or older versions of libraries as will be installed on the target machine?

So my guess is that I don't have a new enough version of libc to link against.
Correct.
Is it a requirement that the version of libc be exactly what the .so file calls out?
No. You need GLIBC-2.11 or newer. See this answer for explanation.

Related

What library has the __main function reference in gcc assembly output

When compiling an empty c program using MinGW the assembly output contains the line
call __main
what library is this from? I expected linking with msvcrt.dll to work (linking using ld), but as it did not, it must be define elsewhere.
There are many related/practically the same question elsewhere, but none of them (as far as I have seen, been searching for a while now) actually contain the answer to this question, so please double check before marking as duplicate.
__main should be provided by the libgcc library, which comes with the MinGW compiler.
If you use the compiler driver (that is, the gcc command-line tool) to link your program, rather than invoking ld directly, this library should be automatically added to the link. Using the compiler driver to link is recommended practice for this and several other reasons.
Depending on exactly which version of MinGW you have and which version of GCC it embeds, libgcc or part of it may be a DLL, which you must bundle if you are shipping MinGW-compiled executables.
On my Windows 10 machine, it is in \Program Files\mingw-w64\x86_64-8.1.0-win32-seh-rt_v6-rev0\mingw64\lib\gcc\x86_64-w64-mingw32\8.1.0\libgcc.a which is then linked directly with the executable, so you do not have to include any DLL with you software.

Link failure with versioned symbols (memcpy & secure_getenv)

I am seeing undefined symbols when trying to link shared libraries with a program on Redhat Linux.
We are running Linux kernel 3.10.0, gcc 4.8.2 with libc-2.17.so, and libblkid 2.23.2
When I build the application I am writing I get two undefined symbols from libblkid: memcpy#GLIBC_2.14 and secure_getenv#GLIBC_2.17. (A very similar build works on other machines, ostensibly using the same versions of everything).
Note, for secure_getenv libblkid wants the same version as the libc library itself.
Looking at the symbols defined in libc-2.17.so I find memcpy##GLIBC_2.14, memcpy#GLIBC_2.2.5, secure_getenv, and secure_getenv#GLIBC_2.2.5. According to my understanding the double # in the first memcpy version is simply supposed to mark it as the default version. And, for some reason even in this libc with versioned symbols the first secure_getenv appears to be unversioned.
So, why does a requirement for memcpy#GLIBC_2.14 not match the defaulted memcpy##GLIBC_2.14?
And logically I would expect the base version of secure_getenv in libc-2.17 to match a requirement for version 2.17.
So, what is going on here? What is making it fail on my development machine and not others? How do I fix this? (As the make works on other machines this appears to be something specific to my build environment, but what?)
You probably have compat-glibc installed, as indicated by the -L/usr/lib/x86_64-redhat-linux6E/lib64 argument. compat-glibc on Red Hat Enterprise Linux 7 provides glibc 2.12 only, so it cannot be used to link against system libraries.

Linking several dependent libraries into my "bare metal" C application

I am developing a bare metal C applications on an ST ARM-Cortex-M3. I have also developed libraries that are usable across all these applications.
I used to use Keil ARM-MDK, but want to move over to GNU-GCC. I thus downloaded the latest version of GCC and started recompiling the code.
Although similar questions to this one have been answered, it does not solve my problem ans therefore I am posting my question.
I have a problem with the following:
Lib_Flash has a function Read_Flash(). Lib_AppCfg links in Lib_Flash as it uses Read_Flash().
My application (App) links in both Lib_Flash and Lib_AppCfg. App also uses Read_Flash() for some specific FLASH checks.
In Keil MDK-ARM it worked fine.
With GCC, when functions using Lib_AppCfg are built, I get errors stating that Read_Flash() is an "undefined reference".
I am not sure where the problem lies. Is it in the linking of the Lib_Appcfg is built or is the problem when I link App?
Please advise. If you need additional information, please let me know.
The GNU linker by default searches the libraries once in the order listed on the command line. So if a library later in the list has a reference to symbol defined in an earlier library or object file, then it cannot be resolved.
The simple solution is to use library grouping; this causes the linker to repeatedly search a list of libraries until no further synbols can be resolved. If you are invoking the linker (ld) separately, then the linker options are:
--start-group _Flash _AppCfg --end-group
or the alternative form
-( _Flash _AppCfg -)
See the GNU linker manual for details. If driving the linker indirectly through gcc you pass linker options via the -Wl option, something like:
-Wl,-(,_Flash,_AppCfg,-)
I think.
It sounds to me like you have got an ordering problem in your libraries. Some linkers will rescan all the libraries on the command line till all references are resolved (or can't be resolved). Other linkers work sequentially along the link line.
In particular, this means that if library A defines a symbol SYM_A and library B which comes after library A references this symbol, it won't be resolved on the 2nd type of linker, and your link will fail.
To get round this, you can do one or more of the following
Reorder the libraries
Replicate libraries on the link line where
necessary
Refactor your libraries so there aren't mutual
dependencies between them (that is A references symbol SYMB, which
is defined in B, but B references SYMA)

Which linker options to include gcc

I compile a project and run it on my system, it does perfectly fine.
I uploaded this to git and asked my administrator to run it on server and it says undefined reference to 'clock_gettime'. This error can be resolved by linking a library with -lrt option. Similar problem happened to me earlier but that was related to linking math.h library with the help of -lm option.
Is there a way to find which all libraries to link so that ou do not run into such problems and not feel embarrassed in front of your administrator. How to decide what all libraries to link. Can there be a thought process for this?
Some man pages will mention both the headers and libraries that should be used. (This is not true of all pages unfortunately.)
For example, look at man 3 signal. On my system that page has a LIBRARY section at the top with Standard C Library (libc, -lc), followed by a SYNOPSIS section with #include <signal.h>.
Some other strategies include:
Blunt use of strings piped to egrep in a shell loop, to search for references to names among installed libraries. This can return a lot of false positives for common names, but it works very well for elaborate function names that don't match single English words.
Iterative compilation and linking. If you are trying to resolve a single function, write a tiny program that calls the function and use a shell or makefile loop to test each single library on your system (starting with a small list of most likely candidates from /usr/lib or wherever else). At some point the build will succeed and show you the right library. This method takes a little work to set up, but the infrastructure you create is also very easy to reuse in the future.
Inspect binaries iteratively using your linker's tools (e.g. otool on Mac OS X, or objdump or readelf on Solaris or Linux). For instance, try to disassemble a library's text section starting from a particular name (otool -v -t -p _symbol on Mac OS X).
For *nix based machines, ldd on the executable will print shared library dependencies.

Copying over glibc library

I downloaded the glibc source code, modified some portion of the standard library and then used LD_PRELOAD to use that modified standard library (in the form of an .so file) with my program. However, when I copied that .so file to another computer and tried to run the same program using LD_PRELOAD there, I got a segmentation fault.
Notice that both computers have x86-64 processors. Moreover, both computers have gcc 4.4 installed. Although the computer in which it is not running has also gcc 4.1.2 installed besides gcc 4.4. However, one is running Ubuntu 10.04 (where I compiled), while the other is running CentOS 5. Is that the cause of the segmentation fault? How can I solve this problem? Notice that I don't have administrative rights on the computer with CentOS 5.
When you LD_PRELOAD the C library, I believe you're loading it in addition to the default C library. When they're the exact same version, all the symbols match, and yours takes precedence. So it works. When they're different versions, you may well have a mix, on a per-symbol basis.
Also, the NSS (name service switch, e.g., all the stuff from /etc/nsswitch.conf) API is not stable. These modules are separate from the main libc.so, but are dynamically loaded when a program e.g., does a user id to username mapping. Loading the wrong version (because you copied libc.so over) will do all kinds of badness.
Further, Ubuntu may be using eglibc and CentOS glibc. So you could be looking at a different fork of glibc.
If your LD_PRELOAD library included only the symbols you actually need to override, and overrode them to the minimum amount possible (e.g., if possible, call the overridden function), then your library has a much higher chance of being portable.
For an example of how to do this, see (for example) fakeroot.
If you're changing so much of libc that your only choice is to override all of it, then (a) you're doing something very weird; (b) you probably want to use LD_LIBRARY_PATH, not LD_PRELOAD; see the ld.so(8) manpage for details.
It is likely that your libc is not portable between kernel versions.

Resources