Linux Dynamic Library plug-in technology (C + +): Dynamic link Library

Source: Internet
Author: User
Tags cos posix

Overview

Plug-in technology is designed for better extensibility. A dynamic link library is one of the ways to implement it.

Here are a few of the main issues discussed.

1) Description of these APIs on Linux. After reading the Linux on the Dlopen and other functions described basic can write a simple dynamic link library use.

2) Some questions and considerations about using the dynamic link library for C + +.

3) extensions, compiler options, dynamic link libraries and static link libraries.


Linux Api:dlopen,dlsym,dlerror,dlclose

Excerpt from Ubuntu Kylin 14.04, kernel 3.13.0-32generic

#include <dlfcn.h>void *dlopen (const char *filename,int flag), char *dlerror (void), void *dlsym (void *handle,const char *symbol); int dlclose (void *handle);
The-LDL option is appended to the link.//note here,-LDL must be placed at the end of the compilation, before writing the program if not added in the end will be an error.

Describe:

These four functions implement a dynamically linked insecure library load interface.

Dlerror ():

Returns a readable string that returns an error of Dlopen,dlsym or Dlclose. Dlerror is just the error message that was returned when the last call was saved.


Dlopen ():

Dlopen loads the dynamic-link library file via filename and returns the handle of the void* type to the dynamic-link library. If filename is null, the main program that the handle points to is returned. If filename contains "/", is interpreted as an absolute or relative path. Otherwise, the dynamic linker searches the library in the following way.

The ELF (executable and linking format) is a form of an object file that defines what is put in different types of object files, and what format they are placed in.// At present, I do not involve such deep things, but simple application. You can temporarily skip the contents of Elf

1) (ELF only) if the executable file contains a Dt_rpath tag but does not contain a dt_rpath tag, it will be searched in the directory listed in the Dt_rpath tab.

2) If the environment variable ld_library_path is defined and contains a colon-delimited list of directories, the directory list is searched.

3) (ELF only) if the executable program contains Dt_runpath tags, the directories listed in the Search tab

4) Check whether the cache file/etc/ld.so.cache contains a library of filename

5) Search Directories/lib/and/usr/lib sequentially

If the filename library is dependent on other shared libraries, the library is dynamically loaded and found in the search method described above.

Flag parameter:

Rtld_lazy: Performs lazy binding, the symbol is parsed only when code that points to the symbol executes. If the symbol has not been pointed to, it will not be resolved. The LAZY binding takes effect only for function references, and when the library is loaded, the reference to the variable is often immediately restricted.

Rtld_now: If the value is specified, or if the environment variable ld_bind_now is a non-null value, all symbols that are undefined in the library are parsed before Dlopen returns. If execution is not completed, an error is returned.

The following parameters can be specified in flag by or.

Rtld_global: Symbols defined in a dynamic library can be parsed by other libraries that are opened later.


Rtld_local: In contrast to Rtld_global, symbols defined in a dynamic library cannot be relocated by other libraries that are subsequently opened. If it is not specified as Rtld_global or rtld_local, the default is rtld_local.


Rtld_nodelete (after glibc2.2): The library is not unloaded during dlclose (), and static variables in the library are not initialized when the library is reloaded with Dlopen () later. This flag is not a POSIX-2001 standard.


Rtld_noload(glibc2.2 later): The library is not loaded. Can be used to test whether the library has been loaded (Dlopen () returns null if the description is not loaded, otherwise the description has been loaded), or it can be used to change the flag of the loaded library, such as the flag for the previously loaded library is Rtld_local,dlopen (rtld_noload| RTLD_GLOBAL) flag will become Rtld_global. This flag is not a POSIX-2001 standard.


Rtld_deepbind(after glibc2.3.4): Search the symbol in the library before searching for the global symbol, avoid the conflict of the symbol with the same name. This flag is not a POSIX-2001 standard.

If filename is a null pointer, returns the handle of the main program. When passed to the Dlsym function call, handle will look for symbols in the main program, find all shared libraries at the start of the program, and find the Dlopen loaded Rtld_global library.

External references in the library are parsed using libraries and library-dependent lists, as well as other libraries that were previously opened with Rtld_global. If a file connection is possible, use-rdynamic or--export-dynamic, The global symbol in the executable file can be used to parse the dynamically loaded library. means that dynamically loaded libraries can refer to symbols in executables. This-rdynamic parameter is then referred to later in this article.

If the same library is loaded again using Dlopen, the same handle will return. The DL library maintains a handle count reference, and a dynamic library is not lifted until the Dlclose function is called. If there is a _init () process, it is called only once. But then Rtld_ The now call may force earlier use of Rtld_lazy loaded libraries for symbolic resolution.

If Dlopen fails, returns NULL.


Dlsys ()use Dlopen's handle and a symbolic name to return the symbol's location in memory. If the symbol is not found in the specified library, and the library is automatically loaded by Dlopen, the return null.dlsym return value may be null. You should save the return value of Dlsym to a variable, and then check whether the saved value is null. The correct way to test the error is to call Dlerrorempty Any old error cases, then call Dlsym, and then call Dlerror.There are two special fake Handle,rtld_default and Rtld_next, (fill in one of these in the handle position). The first one finds the symbol in the default library search order. The second one looks for the next function within the symbol range. these two specific reference connections: (The second connection is more reference value) http://blog.csdn.net/ustcxiangchun/article/details/6310085http://docs.oracle.com/cd/E19253-01/819-7050/6n918j8n4/index.html#chapter3-fig-15

dlclose ()reduce the number of references to the dynamic-link library and unload the dynamic-link library If the reference count is reduced to 0. on success, 0 is returned, and a non-0 value is returned on failure.
WasteDiscarded Symbols _init () and _fini ()If the linker recognizes special symbols _init and _fini. If the dynamic-link library introduces _init (), the INIT code is executed before returning to Dlopen when the library is loaded. Conversely, if you include _fini, The corresponding code is executed before the library is unloaded. The above two deprecated, the library should use __ATTRIBUTE__ ((constructor)) and __attribute__ ((destructor)) Function Properties. Executes at the same time as Init and fini. Read more about GCC information.
gcc Extensions: dladdr () and Dlvsym ()glibc adds a function, but not in POSIX.
#define _GNU_SOURCE/* See Feature_test_macros (7) */#include <dlfcn.h> int dladdr (void *addr, D       L_info *info);       void *dlvsym (void *handle, Char *symbol, char *version);  The function dladdr () takes a function pointer and tries to resolve name and file where it is located.  Information is stored in the Dl_info structure:typedef struct {const char *dli_fname; /* Pathname of shared object that contains address */void *d  Li_fbase; /* Address at which shared object is loaded */const char *dli_snam  E       /* Name of nearest symbol with address lower than addr */void  *DLI_SADDR; /* Exact address of symbol named in Dli_sname */} Dl_info;
If the symbolic address addris not found, Dli_sname and dli_saddr are set to null.dladdr returns 0 for error, and a non-0 value indicates success. the dlvsym,glibc2.1 version provides the same functionality as Dlsym, adding a version string. personally feel that this is not so deep, can ignore the use of these two functions, in the manual, the bug described in some cases DLADRR may be unexpected.
EXAMPLEfinally to the use of time, the reason why the translation of this place is mainly in the online search for some of the information is wrong. Even compile does not pass, unclear what version of the Internet, Compiling is always an error at least for today's use. And look at the examples for proper use. There is a small detail to note.
 Load the math library, and print the cosine of 2.0: #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 */<span style= "color: #ff0000;"              >/* 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"); </span> if (Error = Dlerror ()) = NULL) {fprintf (stderr, "%s\n", error);           Exit (Exit_failure);           } printf ("%f\n", (*cosine) (2.0));           Dlclose (handle);       Exit (exit_success); }
The most important point here is * (void * *) (&cosine) =dlsym (handle, "cos");as noted in the note, the cast may be more natural and understandable, but the C99 standard is undefined for converting void * to function pointers. So it's better to use the sample .At compile time, if the program is inside the FOO.C program file, use the following commandgcc-rdynamic-o foo FOO.C-LDLIf the library contains _init and _fini, compile-time: Gcc-shared-nostartfiles-o bar bar.c.The manual simply describes the compilation of the main program. If you write your own library, the way you use it has been told and compiled as follows.gcc-shared-fpic hello.c-o libhello.so
here are the two parameters-shared and-fpic.-shared, which are shared libraries.-F PIC (position independent code) makes the snippet of the. So file a true share.If-fpic is not added, the data object referenced by the code snippet needs to be relocated when the code snippet for the. So file is loaded, and relocation modifies the contents of the code snippet. This causes every process that uses this. so file snippet to generate a copy of the. So file snippet in the kernel. Each copy is different, depending on the location of the. So file code snippet and the data segment memory map .so, which is not fpic compiled, is re-positioned based on where it was loaded when it is reloaded. (because the code inside it is not a location-independent code).

c plus plus write dynamic link librarybut C + + writing Dlopen is not as simple as C language, design some problems. Reference Connection:http://blog.chinaunix.net/uid-12072359-id-2960897.html

Causes of the cause1) c is different from C + + compile-time naming. Simply speaking C + + to support some features, overloading, and so on, naming rules are more complex. It is not a simple symbol. and C compile-time is a simple symbol. Simply put, the C way to find C + + things can not be found2) C + + contains classes. We need to be loading an instance of a class instead of simply a function pointer.
Solution Solutions1) extern "C"to be blunt is to use C's compile-time naming method. C + + has a specific keyword used to declare a function with C binding: extern "C". Functions declared with extern "C" will use a function name, just like a C function. Therefore, only non-member functions can be declared as extern "C" and cannot be overloaded. Despite the limitations, extern "C" functions are useful because they can be dynamically loaded like C functions by Dlopen. With the extern "C" qualifier, it does not mean that C + + code is not available in the function, but instead it is still a complete C + + function that can use any C + + attribute and various types of parameters.
2) Load classes with polymorphism.a base class points to a derived class that is instantiated through a function. an interface base class with a virtual member function is defined in the executable, and a derived implementation class is defined in the module. In the module, define two additional helper functions, which is known as the class factory function (classes factory functions) where one of the functions creates a class instance and returns its pointer; The other function is used to destroy the pointer. Both functions use extern "C" to qualify the adornments.
----------//main.cpp://----------#include "polygon.hpp" #include <iostream> #include <dlfcn.h>int main    () {using Std::cout;    Using Std::cerr;    Load the triangle library void* triangle = Dlopen ("./triangle.so", Rtld_lazy);        if (!triangle) {cerr << "Cannot load library:" << dlerror () << ' \ n ';    return 1;        }//Reset errors Dlerror ();    Load the symbols create_t* Create_triangle = (create_t*) dlsym (triangle, "create");    Const char* Dlsym_error = Dlerror ();        if (dlsym_error) {cerr << "Cannot load symbol create:" << dlsym_error << ' \ n ';    return 1;    } destroy_t* Destroy_triangle = (destroy_t*) dlsym (triangle, "destroy");    Dlsym_error = Dlerror ();        if (dlsym_error) {cerr << "Cannot load symbol destroy:" << dlsym_error << ' \ n ';    return 1;    }//Create an instance of the class polygon* poly = Create_triangle (); Use the CLASS Poly->set_side_length (7);    cout << "The area is:" << poly->area () << ' \ n ';    Destroy the class Destroy_triangle (poly); Unload the Triangle Library dlclose (triangle);} ----------//polygon.hpp://----------#ifndef polygon_hpp#define polygon_hppclass Polygon {protected:double Side_ Length_;public:polygon (): side_length_ (0) {} virtual ~polygon () {} void Set_side_length (double Side_leng    TH) {side_length_ = Side_length; } virtual double area () const = 0;};/ /The types of the class Factoriestypedef polygon* create_t (); typedef void destroy_t (polygon*); #endif//----------// triangle.cpp://----------#include "polygon.hpp" #include <cmath>class triangle:public polygon {public:virtual D    Ouble area () const {return side_length_ * side_length_ * sqrt (3)/2; }};//the class Factoriesextern "C" polygon* Create () {return new triangle;} extern "C" void Destroy (polygon* p) {delete p;}

Precautions:1) In a module or shared library, a creative function and a destroy function are provided.2) The destructor of the interface class must be virtual (virtual) in all cases

Extended
Compiler Optionsat compile time, there is a-rdynamic in the main program module. Two parameter-shared-fpic when writing a library .-rdynamic:rtld_global makes the external interface between the dynamic libraries visible, but the dynamic library is not able to invoke the global symbol in the main program, in order to solve this problem, GCC introduced a parameter-rdynamic, When the executable program is loaded into the shared library, the last time you add-rdynamic to the link, it will make all the symbols in the executables globally visible, and for this executor, the dynamic library it loads can call the global symbols in the main program directly in the run, and if the shared library ( yourself or another shared library Rtld_global) plus has a symbol with the same name, which selects the symbols used in the executable, which in some cases may cause some inexplicable run errors. Reference Link: http://blog.csdn.net/uestcleo/article/details/7727057
when writing a program, one of the errors encountered is that-shared-fpic does not add the-c parameter, otherwise the compilation fails.

dynamic libraries and static librariessimply put, the static library, is in each program to link the time the library in the target program to make a copy, when the target program is generated, the program can be separated from the library files run alone. The contents of the library are already included in the generated program.

Shared libraries can be shared by multiple applications and dynamically loaded when the program is running.
Reference:http://www.cnblogs.com/luoxiang/p/4168607.htmlhttp://www.cnblogs.com/skynet/p/3372855.html



















Linux Dynamic Library plug-in technology (C + +): Dynamic link library

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.