Dynamic lib may be the widely used mechanism for code reusing and memory saving, both for Windows and UNIX/Linux systems. To better understand the dynamic lib, we will try to fix the famous error during linking and investigate the symbols within the lib.
0. ldd
ldd cmd is used to display the necessary dynamic lib used by certain binary file.
root@arpsec01:~/tpm/rpc# ldd rpc
linux-vdso.so.1 => (0x00007ffff9bff000)
libtspi.so.1 => /usr/lib/libtspi.so.1 (0x00007fc6ec53e000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc6ec17f000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc6ebf61000)
libcrypto.so.1.0.0 => /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 (0x00007fc6ebb86000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc6ec7c4000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc6eb982000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fc6eb76a000)
root@arpsec01:~/tpm/rpc#
1. Error while loading shared libraries: XXX.so.xxx
a. The dynamic lib is missing – install
b. The lib has been installed under /lib or /usr/lib – ldconfig
c. The lib has been installed under somewhere else, like /usr/local/lib – ld.so.conf
# cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
# echo “/usr/local/lib” >> /etc/ld.so.conf
# ldconfig
d. The lib has been installed somewhere else and temporary linking is needed – LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
2. How could I know what (functions/variables) are contained by certain dynamic lib?
Generally speaking, there are 2 ways to do that.
a. nm -C -D path_to_a_dynamic_lib – nm is so powerful that it will list all the symbols contained by this dynamic lib, including functions (T) and variables. The most common case for nm would be ‘nm -C -D path_to_a_dynamic_lib | grep function_name’, which is used to determine if certain function is contained by this dynamic lib.
root@arpsec01:~# nm -C -D /usr/lib/libtspi.so | grep RPC_OpenContext_TP
000000000001f9d0 T RPC_OpenContext_TP
root@arpsec01:~#
b. dlsym() – actually a system call interfacing with ld. dlopen() is used to open certain dynamic lib and dlsym() then could be used to check if certain symbol is contained or not. Example code is below.
root@arpsec01:~/ld_blog# cat myld.c
/*
* myld.c
* example source to use dl* functions
* to parse the content of a dynamic lib
* Usage: myld libname symbol
* Sep 2, 2013
* root@davejingtian.org
* http://davejingtian.org
*/
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char *argv[])
{
void *handle;
void *addr;
if (argc != 3)
{
printf(“Error: Missing parameters\n”);
return -1;
}
/* Get the handle of the lib */
handle = dlopen(argv[1], RTLD_NOW);
if (handle == NULL)
{
printf(“Error: dlopen %s [%s]\n”, argv[1], dlerror());
return -1;
}
/* Try the get the address of symbol */
addr = dlsym(handle, argv[2]);
if (addr == NULL)
{
printf(“Error: dlsym %s [%s]\n”, argv[2], dlerror());
dlclose(handle);
return -1;
}
printf(“Symbol[%s]@0x%x\n”, argv[2], addr);
dlclose(handle);
return 0;
}
root@arpsec01:~/ld_blog# gcc -o myld myld.c -ldl
myld.c: In function ‘main’:
myld.c:42:2: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘void *’ [-Wformat]
root@arpsec01:~/ld_blog# ./myld libtspi.so RPC_OpenContext_TP
Symbol[RPC_OpenContext_TP]@0x917449d0
root@arpsec01:~/ld_blog#
3. Functions(symbols) are the memory address, so what?
root@arpsec01:~/ld_blog# cat myld2.c
/*
* myld2.c
* Load the math library, and print the cosine of 2.0
* Reference: man 3 dlsym
* Sep 2, 2013
* root@davejingtian.org
* http://davejingtian.org
*/
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int
main(int argc, char **argv)
{
void *handle;
double (*cosine)(double);
char *error;
handle = dlopen(“libm.so”, RTLD_LAZY);
if (!handle) {
fprintf(stderr, “%s\n”, dlerror());
exit(EXIT_FAILURE);
}
dlerror(); /* Clear any existing error */
/* Writing: cosine = (double (*)(double)) dlsym(handle, “cos”);
would seem more natural, but the C99 standard leaves
casting from “void *” to a function pointer undefined.
The assignment used below is the POSIX.1-2003 (Technical
Corrigendum 1) workaround; see the Rationale for the
POSIX specification of dlsym(). */
*(void **) (&cosine) = dlsym(handle, “cos”);
if ((error = dlerror()) != NULL) {
fprintf(stderr, “%s\n”, error);
exit(EXIT_FAILURE);
}
printf(“%f\n”, (*cosine)(2.0));
dlclose(handle);
exit(EXIT_SUCCESS);
}
root@arpsec01:~/ld_blog# gcc -o myld2 myld2.c -ldl
root@arpsec01:~/ld_blog# ./myld2
-0.416147
root@arpsec01:~/ld_blog#