C Programming

Linux Dlopen System in C

The library function dlopen() is a very useful function in the C language. The function loads the library into the memory after opening a new one. We generally use it to load the library symbols that are unknown at the compile time. Dlopen() is a function that is used in our programs. The DL library implements dlopen(), defined in Dlfcn.h. Two parameters are required for the dlopen function: the name of the library file and the flag. The file’s name is a dynamic library, and it defines whether or not the library’s dependencies are calculated right away. The dlopen() returns a “handle” which should be regarded as an opaque value and other DL library operations use this. If the attempt to load is unsuccessful, dlopen() returns NULL. But the dlopen() returns the same file handle if it loads the same library many times.

While utilizing the dlopen function, the compiler does not examine for potential errors since it is unaware of the types and prototypes that we are using. The deployment of the dlopen function for standard loading does not appear to be promoted by it, except for a few minor situations. By the way, it’s an approach to improve introspection. When the shared module is currently being utilized by another program, the memory layout optimization is not particularly interested in conditional loading. The memory footprint does not increase when a previously used library is loaded. Avoiding the compiler monitoring is dangerous and makes for good bug writing. Additionally, we lack the possible compiler optimization.

Example 1:

Now, consider the following example to see the functionality of the dlopen function in the C language. In the first step, we load some C standard libraries. Here, we load the new library “dlfcn.h” which is used to define the macros while constructing the dlopen mode argument.

Then, we introduce another library inside our program “gnu/lib-name.h”. The shared library files included with GNU libc are found by the user programs according to the macros that it defines. The GNU C Library offers the fundamental libraries for the GNU and GNU/Linux operating systems as well as a wide range of other Linux-based systems. After that, we have the main method implementation. Inside that, we declare the pointer object “handle” with the void keyword. We declare a pointer sine function that has the data type double. There is another declaration of the pointer object “error” for error handling.

After that, we invoke the dlopen function inside the “handle” object. The dlopen takes two arguments: LIBM_SO and “RTLD_LAZY”. Here, “LIBM_SO” is the name of the library file which provides mathematical functions like trigonometric functions. This shared library is required as we use the sine function. The “RTLD_LAZY” is another argument that calls the dlopen function. When a given symbol is referenced the first-time, relocations must be carried out at a time determined by the implementation.

Since a process may not reference every symbol in an executable object file, specifying the RTLD LAZY should enhance the performance on implementations that enable the dynamic symbol binding. Next, we have an if-else condition for error handling when the handle object fails to perform the dlopen function. We call the dlerror to clear the error.

The dlerror() function provides a null-terminated string that is human-readable and specifies the reporting of the recent error that is caused by a call to one of the dlopen API calls since the last dlerror call. Then, we cast the function like this: “(*void**)(&sine)= dlsym(handle, sin)”. As this is strange, casting complies with ISO C which avoids warnings from the compiler. We employ the dlsym function which gets the path of a symbol that is specified inside a dynamic link module which is accessible via a dlopen() function.

Also, we perform the if-else operation again for the standard error which is generated when the dlerror() is not NULL. Then, we have a printf statement where we specify the sine value to be computed. In the last step, we close that shared object by invoking the dlclose for the handle returned by the dlopen().

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <gnu/lib-names.h>

int
main(int argc, char **argv)
{
    void *handle;
    double (*sine)(double);
    char *error;

   handle = dlopen(LIBM_SO, RTLD_LAZY);
    if (!handle) {
        fprintf(stderr, "%s\n", dlerror());
        exit(EXIT_FAILURE);
    }
   dlerror();  

   *(void **) (&sine) = dlsym(handle, "sin");

   if ((error = dlerror()) != NULL)  {
        fprintf(stderr, "%s\n", error);
        exit(EXIT_FAILURE);
    }

   printf("%f\n", (*sine)(4.0));
    dlclose(handle);
    exit(EXIT_SUCCESS);
}

We use the -ldl option with the C compilation command since this is the library for the dlopen linked interface and it is required. When the execution of the dlopen file is made, it displays the sine value of the previously-given value.

Example 2:

Now, we take another example of using the dlopen function. We load our program with all the required C libraries for the implementation of the dlopen code. Then, we start our program inside the main method. Here, we define the string with the declaration of the variable “src”. We then declare the pointer variables “strlen”, “handle” and “error”.

Next, we call the handle variable and deploy the dlopen function. The dlopen function inputs the shared library “libstr.so” for string handling functions and the flag “RTLD_LAZY” which is already demonstrated in the previous example. We invoke the dlerror function inside the “error” variable to clear the error generated by the dlopen function. The if-else is utilized to examine the errors.

Then, we obtain the strlen function’s address using the dlsym function and verify the errors while doing this. After this, we use the printf function to call the strnlen function to return the length of the given string. In the end, we close the shared library with the dlclose function.

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <gnu/lib-names.h>
int main(void)
{
  char* src = "Hello Linux";
  int (*strlen) (const char *);
  void *handle;
  char *error;
   

  handle = dlopen("./libstr.so", RTLD_LAZY);
  error = dlerror();
  if(!handle || error != NULL){printf("Loading Library Attempt Failed!\n%s\n", error);
  return -1;}
   
  strlen = dlsym(handle, "strlen");
  error = dlerror();
  if(!strlen || error == NULL){printf("%s\n", error);return -1;}

  printf("The Length of the String is:%d\n",strlen(src));
  dlclose(handle);
  return 0;
}

We use the following command for the execution of the given program. Here, the -lstr flag is used for the string length function and the ldl is used for the dlopen library file. The compiled program gives the length of the string as shown in the shell:

Conclusion

The information is provided regarding the dlopen function of the C language in this article. We have a brief introduction of the dlopen function. Then, we implemented two examples. The function returns an identifier that defines the opened library. The addresses of the functions inside the opened library are then determined using this identifier and the dlsym function. A function’s address within a library that has already been opened using dlopen can be found using the dlsym function.

About the author

Omar Farooq

Hello Readers, I am Omar and I have been writing technical articles from last decade. You can check out my writing pieces.