LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Articles > Technical
User Name
Password

Notices


By Seedhom at 2009-11-03 04:39
Once you create a set of functions that you like to reuse in multiple programs, you typically build them into a library. The norm in Linux now has moved away from Static libraries (*.a) and more towards Shared Libraries (*.so). Shared libraries can either be linked-in at compile time from a specific location on the system using -l and -L flags or can be loaded dynamically while the program is executing. There are advantages and disadvantages for each of those 2 cases. However, without going into depth about this, let me describe a case where dynamic loading of a shared library is most relevant.

Assume I am writing a server with the purpose to serve applications to users. A typical case is when the user runs a client front-end application from which he makes requests to the server to execute other applications on the server side. The requested applications has to be available to the server in the form of a loadable objects. These loadable objects or shared libraries do not have to be predefined to the server before it starts, nor does the server need to know what they do once they are loaded. All the server needs to know is where these libraries are in its file system and the name of the function the user needs to call.

The example I am going to show here is not as elaborate as an application server, but it will show the technique fully.


The Shared Library
Start with the shared library I want to create with a trivial code:
Code:
#include <stdio.h>

int main(int argv, char *argc[])
{
	printf("Hey World - I am loaded\n");
}
Let us save this file as a C++ file just for kicks and call it myloadingtest.cpp
To compile the above code as a shared library, we will do this in 2 steps:
  • (1) Compile using the -fPIC flag :
    This will generate a position-independent code (PIC) so the OS dynamic loader can position it as it sees fit. Here is the compile line
    Code:
    g++ -fPIC -c myloadingtest.cpp
    (2) Generate the shared library from the object we just created:[/li] We will need the -shared flag to tell that to the compiler. I am going to name the lib libmyloadingtest.so. Here is the line:
    Code:
    g++ -shared  -o libmyloadingtest.so myloadingtest.o

Now we have a shared library with only one entry: main(int, char **) in it.

Now for the loading application (or server)...


Shared Library Loader:
Let me jump right away into the code:
Code:
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>

int main(int argc, char *argv[]) 
{
        void *handle;          // Pointer to the library location
        int (*mymain)(void);   // Pointer to point to the function in the lib to execute
        char *error;           // Pointer to the error that maybe returned by the dlerror() call

        // load the shared lib using Run Time Loader lazy mode
        handle = dlopen ("./mydynlibs/libmyloadingtest.so", RTLD_LAZY);
        if (!handle) 
        {
            printf("This is an error in loading \n");
            exit(1);
        }
        printf("Library loaded successfully. Finding the function we need ..\n");

        // Resolve the function call ..
        mymain = (int (*)())dlsym(handle, "main");
        if ((error = dlerror()) != NULL)  
        {
            printf("Error: I did NOT find the symbol 'main' \n");
            exit(1);
        }
        printf("Success: Symbol 'main' was found. Calling it now ..\n");
        
              
        mymain(); // Call the function entry in the library
        
        dlclose(handle);
    }
Save the above code as file a C++ file dynamic_libload.cpp
To compile, use this line
Code:
g++ -g  dynamic_libload.cpp -o dynamic_libload -ldl
That is it!!

Now a couple of points:
There are only 2 calls needed to load a shared library dynamically:
Code:
void *handle = dlopen ("/path/to/lib/mylibname.so", RTLD_LAZY); 
...
dlclose(handle);
And 2 calls are needed for each function symbol you need to point to:
Code:
myfunc_ptr = (<type> (*)())dlsym(handle, "function_name");
// if myfunc_ptr turns NULL, then call
error = dlerror()
Another note to make about the option used in dlopen() call: You can either use RTLD_LAZY or RTLD_NOW. The first is the LAZY option which allows the loader to bind the library IF and only WHEN a function call is made to one of the library functions. The NOW option forces the loader to bind and resolve all the symbols in the shared library before the dlopen() returns. That could be a waste of time if for some reason the program decides not to call any of its functions.


- Al Sabawi (Seedhom)
Nov. 2, 2009

by johnsfine on Tue, 2011-02-22 15:12
I only got as far as the second paragraph there before seeing something I think is a wrong enough direction that it deserves correction:

Quote:
Assume I am writing a server with the purpose to serve applications to users. A typical case is when the user runs a client front-end application from which he makes requests to the server to execute other applications on the server side. The requested applications has to be available to the server in the form of a loadable objects. These loadable objects or shared libraries do not have to be predefined to the server before it starts, nor does the server need to know what they do once they are loaded. All the server needs to know is where these libraries are in its file system and the name of the function the user needs to call.
I can think of almost unlimited reasons why that should be done as separate processes launched by the server, and almost no reasons why you would consider doing it via .so files loaded into the server process address space.

I know it may be hard to think of an example that is realistic while still being simple enough to work through. But this choice of example gets the whole article off to a bad start.

Edit: Now I read the whole page there. That paragraph I complained about just distracts the reader and may cause some readers to go away before reading the useful parts. It doesn't really introduce what follows.

I don't think you even need that kind of ("what is it for") introduction to what follows. The example stands better alone without the lame introduction. If you do need an introduction, it should be a more reasonable one.


  



All times are GMT -5. The time now is 10:30 AM.

Main Menu
Advertisement
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration