Why symbols of a shared library are not resolved at link time? - c++

This is my 2nd post on this site in my effort to understand the compilation/linking process with gcc. When I try to make an executable, symbols need to be resolved at link time, but when I try to make a shared library, symbols are not resolved at link time of this library. They will perhaps be resolved when I am trying to make an executable using this shared library. Hands-on:
bash$ cat printhello.c
#include <stdio.h>
//#include "look.h"
void PrintHello()
{
look();
printf("Hello World\n");
}
bash$ cat printbye.c
#include <stdio.h>
//#include "look.h"
void PrintBye()
{
look();
printf("Bye bye\n");
}
bash$ cat look.h
void look();
bash$ cat look.c
#include <stdio.h>
void look()
{
printf("Looking\n");
}
bash$ gcc printhello.c printbye.c
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
/tmp/cck21S0u.o: In function `PrintHello':
printhello.c:(.text+0x7): undefined reference to `look'
/tmp/ccNWbCnd.o: In function `PrintBye':
printbye.c:(.text+0x7): undefined reference to `look'
collect2: ld returned 1 exit status
bash$ gcc -Wall -shared -o libgreet printhello.c printbye.c
printhello.c: In function 'PrintHello':
printhello.c:6: warning: implicit declaration of function 'look'
printbye.c: In function 'PrintBye':
printbye.c:5: warning: implicit declaration of function 'look'
So my question is why are symbols not resolved when I am linking a shared library. This work(Resolving symbols of its downstream) will need to be done when I will use this library to make an executable, but that means we need to know what this library depends on when using this library, but isn't it not undesirable?
Thanks,
Jagrati

Does adding -z defs when building the library do what you want? If not, check the ld man pages, there are quite a few options on the handling of undefined symbols.

Since you didn't give the -c (compile only) option, you requested gcc to compile the two source files and link them with the standard library (libc) and the c run-time startup (crt0, typically) to produce a running program. crt0 tries to enter your program by calling main(), which is the undefined symbol the linker can't find. It can't find it because you don't have a main() in either of your .c files, right?
So, on to your actual question, "Why symbols of a shared library are not resolved at link time?" The answer is, what do you mean by "link time?" By defintion, a dynamically linked program isn't "linked" until it starts (or maybe not even then, depending on your system.)
On a Linux system, you can see which dynamic libraries a program depends on with the ldd command (on Mac OS use 'otool -L'). The output of ldd will tell you which dynamic libraries a program depends on, which where found in the library search path, and which ones cannot be found (if any).
When you dynamic program starts, the dynamic linker that was linked into it locates and loads the dynamic libraries the program depends on, and "fixes" the references to the external symbols. If any of these fail, your program will fail to start. One all of the formerly unresolved symbols have been resolved, the dynamic linker returns and the C runtime will call your main() function. (It's somewhat different on Mac OS, but similar in effect, the linking happens after your program is started.)

I think the linker option -Bsymbolic is what you're looking for.

The linked has no way of knowing, in ELF at least, where the symbols are (i.e. in which libraries). In OS X, on the other hand, you need to link libraries the way you described. In the end, it is a question of design. One is more flexible, the other, more rigorous.

Even when you build a shared library it must resolve all the dependencies.
Thus when a shared library is loaded at compile time it knows what other shared libraries to load at runtime so that it can resolve other dependencies.
1) Build a shared (look.<sharedLib>) library with look()
2) Build a shared (hg.<sharedLib>) library with hello() bye() link against look.<sharedLib>
3) Build Application with main() that links against hg.<sharedlib>
At runtime the application will then load hg.<sharedlib> which will intern load the shared library look.<sharedlib>

A executable requires a entry point. But a shared library can be built without the entry point and later the executable can be compiled with this shared library.

Related

Does Windows linker resolve undefined symbols in DLL with LoadLibrary?

In Linux when I load shared library using dlopen() from executable (or shared library) I expect that undefined symbols in this library will be automatically resolved, of course as long as executable (or shared library) defines these symbols.
For example, I have library A with these header and source files:
#pragma once
int funcA();
#include "A/header.h"
int funcA() {}
also I have library B with this source file:
#include "A/header.h"
void funcB() {
funcA();
}
for library B I specify path to header of library A, but I don't link library A to library B.
In this case, if I load library B from library A by calling dlopen(), then undefined symbol funcA in library B will be resolved, so library B will be able to call funcA.
Is it also true for Windows, or I have to manually find addresses for all symbols I need?
After researching already answered questions on Stack Overflow:
External symbol resolving in a dll
Compile to .dll with some undefined references with MinGW
I realized that if I want to make something similar work on Windows, I have to create some import library for my shared library A.
At first I thought it's needed only for MSVC, but looks like MinGW needs import library too, because it's how things work on Windows. Correct me if I miss something.
For me it's big no-no, so probably I will change a way how I work with shared libraries to explicitly retrieve every symbol I need via additional interface. Fortunately, there are not so many of them.

[c++][cygwin][gcc] Boost Filesystem linking from DLL via BOOST_FILESYSTEM_DYN_LINK

I've very simple piece of code witch utilize Libboost filesystem to check if file exist or not. Additionally I want to use libboost as dll library, not static one. Here you have what I written few minutes ago:
void Hex2bin::convert(string filename, vector<uint8_t>* decodedBytes) {
const path fname(filename); // from boost::filesystem
if (exists(fname)) {
;
}
else {
throw new EFileDoesntExist;
}
}
Unfortunately when I remove -lboost_filesystem from linker settings and add macro BOOST_FILESYSTEM_DYN_LINK globally in Eclipse configuration I get only such linker error as below:
/usr/include/boost/filesystem/operations.hpp:446: undefined reference to `boost::filesystem::detail::status(boost::filesystem::path const&, boost::system::error_code*)'
Source file compiles without any warning. When I revert back to -lboost_filesystem everything works OK, but I assume that then library is statically linked to EXE file. Have anybody any idea what is going wrong? Or maybe I have wrong understanding how libboost can be linked?
No. You still need to specify-lboost_filesystem even if the library is a shared object rather than a static library. In fact, most linkers will prefer to link against a shared object rather than a .a if both are present (there are ways to change this if necessary).
Use ldd to see the shared libraries an executable is linked against.
Only Windows (specifically MSVC++) supports "auto-linking" with Boost. On Linux, you'd either link against libboost_filesystem.so or libboost_filesystem.a, but in either case you need to link explicitly.

C++ compiles and links with pointer to undefined function

This code:
void undefined_fcn();
void defined_fcn() {}
struct api_t {
void (*first)();
void (*second)();
};
api_t api = {undefined_fcn, defined_fcn};
defines a global variable api with a pointer to a non-existent function. However, it compiles, and to my surprise, links with absolutely no complaints from GCC, even with all those -Wall -Wextra -Werror -pedantic flags.
This code is part of a shared library. Only when I load the library, at run-time, it finally fails. How do I check, at library link-time, that I did't forget to define any function?
Update: this question mentions the same problem, and the answer is the same: -Wl,--no-undefined. (by the way, I guess this could even be marked as duplicate). However, according to the accepted answer below, you should be careful when using -Wl,--no-undefined.
This code is part of a shared library.
That's the key. The whole purpose of having a shared library is to have an "incomplete" shared object, with undefined symbols that must be resolved when the main executable loads it and all other shared libraries it gets linked with. At that time, the runtime loader attempts to resolve all undefined symbols; and all undefined symbols must be resolved, otherwise the executable will not start.
You stated you're using gcc, so you are likely using GNU ld. For the reason stated above, ld will link a shared library with undefined symbols, but will fail to link an executable unless all undefined symbols are resolved against the shared libraries the executable gets linked with. So, at runtime, the expected behavior is that the runtime loader is expected to successfully resolve all symbols too; so the only situation when the runtime loader fails to start the executable will indicate a fatal runtime environment failure (such as a shared library getting replaced with an incompatible version).
There are some options that can be used to override this behavior. The --no-undefined option instructs ld to report a link failure for undefined symbols when linking a shared libraries, just like executables. When invoking ld indirectly via gcc this becomes -Wl,--no-undefined.
However, you are likely to discover that this is going to be a losing proposition. You better hope that none of the code in your shared library uses any class in the standard C++ or C library. Because, guess what? -- those references will be undefined symbols, and you will fail to link your shared library!
In other words, this is a necessary evil that you need to deal with.
You can't have the compiler tell you whether you forgot to define the function in that implementation file. And the reason is when you define a function it is implicitly marked extern in C++. And you cannot tell what is in a shared library until after it is linked (the compiler's linker does not know if the reference is defined)
If you are not familiar with what extern means. Things marked extern signal external linkage, so if you have a variable that is extern the compiler doesn't require a definition for that variable to be in the translation unit that uses it. The definition can be in another implementation file and the reference is resolved at link time (when you link with a translation unit that defines the variable). The same applies for functions, which are essentially variables of a function type.
To get the behavior you want make the function static which tells the compiler that the function is not extern and is a part of the current translation unit, in which case it must be defined -Wundefined-internal picks up on this (-Wundefined-internal is a part of -Werror so just compile with that)

GCC Linking a shared library against an executable

I have the following problem. I have a shared library, which is just a bunch of translation units linked together so when I compile that shared library I won't get any linker error (undefined references, even though I might have).
The shared library gets loaded dynamically from an executable which also contains the exports which my shared library is using (The references used in my library are resolved at runtime).
The main problem is that I want the undefined reference warnings so I can fix them statically instead of waiting the application to crash.
I read somewhere that I can pass "-Wl,--no-undefined" to gcc so I can get these errors back, indeed it worked but it also gave me all the undefined references of the executable's exports. I want to filter these warnings just to the scope of my translation units.
Is this possible? If not, how can I define reference to a executable which has exports for a shared library.
you can try linking the library & main program with -Wl,-z,now. that should make the runtime ldso resolve all references immediately and throw an error if none are found.
otherwise, i'm not seeing an option off hand in the linker manual to say "allow this ELF to satisfy symbols, but don't actually list it as a DT_NEEDED".
you could try using -Wl,--no-undefined and parsing the output with a script so you can filter out symbols you know will be satisfied by the main program.
another option might be to label all the symbols you know the main program provides with __attribute__((weak)) and then still use -Wl,--no-undefined. the weak symbols won't be reported as an error.

How to make gcc/ld iterate over many '-l library' when using -static?

I want to compile statically pdf2svg so I will be able to use newest version in stable Debian. The ./configure doesn't give --enable-static option so I added manually in Makefile -static option for linker.
Unfortunately the result wasn't quite as I suspected. The linking gave me enormous amounts of undefined reference errors. After some googling I figured out that the problem is caused by wrong order of -lsome_lib. Gcc linker tries to statically link in each library once, when it first sees it - info and Stackoverflow question: Why does the order in which libraries are linked sometimes cause errors in GCC?.
Is there a possibility of making linker make multiple passes through the list of libraries?
Maybe this is what you search for (from gnu ld manpage):
-( archives -)
--start-group archives --end-group
The archives should be a list of archive files. They may be either explicit file names, or -l options.
The specified archives are searched repeatedly until no new undefined references are created. Normally, an archive is searched only once in the order that it is
specified on the command line. If a symbol in that archive is needed to resolve an undefined symbol referred to by an object in an archive that appears later on
the command line, the linker would not be able to resolve that reference. By grouping the archives, they all be searched repeatedly until all possible references
are resolved.
Using this option has a significant performance cost. It is best to use it only when there are unavoidable circular references between two or more archives.
A tick is, whenever possible, to add a static reference to an object of the class (or to the function) that were not linked in another cpp file of the same library (or in another library already used).
I have this situation:
library A with class clsA in clsA.cpp that gives the error
library A with foo.cpp that gives no reference errors
library B that uses class clsA
Application uses both libraries and uses classes/functions from foo.cpp
I get the unresolved reference in Application while using the object in library B that uses the clsA class.
Linking Application with library A and B give me the error. Since i use CodeLite, it's hard to change library order. I simply put a static object in foo.cpp:
#include "clsA.h"
clsA objA;
The linker now see that clsA are referenced in library A (between foo.cpp) and will link correctly in application because foo.cpp were already linked.
But the trick works even if the object were created in a dummy function, never called, so the object would never been allocated:
// foo.cpp
#include "clsA.h"
void dummyf()
{
clsA objA;
}