Linux dynamic library compilation and usage detailed analysis, linux dynamic compilation Analysis
Introduction
This article focuses on some operations on using gcc to compile dynamic libraries on linux and provides in-depth case analysis.
Finally, we will introduce the dynamic library plug-in technology to make the code backward compatible,
Pre-compile, compile, and generate the final link of the mechanical Code. For the output executable file process, refer to the following.
Gcc compiling process http://www.jb51.net/article/46407.htm
This article focuses on analyzing knowledge points related to the dynamic library. First, let's take a look at the testing materials needed.
Heoo. h
# Ifndef _ H_HEOO # define _ H_HEOO/** test interface to obtain the key content *: returns the key string */extern const char * getkey (void);/** test interface, get value content * arg: input parameter *: returned result */extern void * getvalue (void * arg); # endif //! _ H_HEOO
Heoo-getkey.c
# Include "heoo. h"/** test interface, get the key content *: returns the key string */const char * getkey (void) {return "heoo-getkey.c getkey ";}
Heoo-getvalue.c
# Include "heoo. h "# include <stdio. h>/** test interface, get value content * arg: input parameter *: return result */const void * getvalue (void * arg) {const char * key = "heoo-getvalue.c getvalue"; printf ("% s-% s \ n", key, (void *) arg); return key ;}
Heoo. c
# Include "heoo. h "# include <stdio. h>/** test interface to obtain the key content *: returns the key string */const char * getkey (void) {return "heoo. c getkey ";}/** test interface to obtain the value content * arg: input parameter *: returned result */const void * getvalue (void * arg) {const char * key = "heoo. c getvalue "; printf (" % s-% s \ n ", key, (char *) arg); return key ;}
Main. c
# Include <stdio. h> # include "heoo. h "// test the logical main function int main (int argc, char * argv []) {// print data printf (" getkey => % s \ n ", getkey (); getvalue (NULL); return 0 ;}
It may feel a little bloated here, but it is necessary to understand why it will make your dynamic library highly up to 0.01mm. Haha.
Let the above Code run first.
gcc -g -Wall -o main.out main.c heoo.c
The test results are as follows:
After the test is completed, start the expansion of static databases to dynamic databases.
Preface
Speaking of static library
First, refer to the following compilation statement
gcc -c -o heoo-getkey.o heoo-getkey.cgcc -c -o heoo-getvalue.o heoo-getvalue.c
Static Library Creation is essentially packaging. Therefore, use an ar on linux to create static library compression commands. For detailed usage, see
Ar detailed usage reference http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201121093917552/
Then we start to create a static library.
ar rcs libheoo.a heoo-getvalue.o heoo-getkey.o
Then we use the static library to compile the above main. c function.
gcc -g -Wall -o main.out main.c -L. -lheoo
Run the following:
Everything is running normally. For the static library compilation, a brief description is given. The rcs following ar indicates replacing the creation and adding the index. For details, refer to the above URL.
-L indicates the directory of the database to be searched in gcc, and-l indicates the libheoo library to be searched. other-I parameters are used to find the header file address, and-D indicates to add a Global Macro .......
There is another way to compile the above static Library:
gcc -g -Wall -o main.out main.c libheoo.a
The execution results are the same. You can think of *. a as multiple *. o elements.
Now, the preface is complete. We will start to talk about the dynamic library of the subject.
Body
Dynamic Library Construction and Use
The dynamic library construction name is as follows, and heoo. c heoo. h is still used as an example.
gcc -shared -fPIC -o libheoo.so heoo.c
To compile the code, first introduce the simplest method, which is similar to the last method of the above static library.
gcc -g -Wall -o main.out main.c ./libheoo.so
The result is as follows:
If libheoo. so is used directly when the above dynamic library is compiled, for example
gcc -g -Wall -o main.out main.c libheoo.so
If the dynamic library path is not configured, a problem may occur when searching for the dynamic library path. This will not happen again (because I have adjusted the Environment). A solution will be provided during the meeting.
The following describes how to use libheoo. so.
gcc -g -Wall -o main.out main.c -L. -lheoo
The running result is as follows:
The above is a common error. The system cannot find the dynamic library. You need to configure it and compile it as follows:
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH;./"gcc -g -Wall -o main.out main.c -L. -lheoo
The first sentence above is in the current Session Layer. Add the library search path, including the current file directory. This session layer is disabled and becomes invalid. shell on Linux is really important. Now the execution result
Now the dynamic library is complete. Everything is normal.
A clever trick
Q: When gcc-l is used to link a library, but there are static and dynamic libraries in the library with the same name. Which library will be linked?
Through the above tests, we should know that it is a dynamic library, because an error will be reported when using the dynamic library. There is no problem with using the static library.
So what should I do if I want to use a static library.
-Static
The above gcc options can help us forcibly link static libraries!
Dynamic library display and usage
Here is basically the most important thing. Even a little bit, these knowledge points have changed in the Windows knowledge environment, and the settings have changed. All links are compiled and loaded explicitly. below is the re-operation code.
Heooso. c
# Include <stdio. h> # include <dlfcn. h> # define _ STR_PATH ". /libheoo. so "// display the call to the dynamic library, you need to-ldl Link Library int main (int argc, char * argv []) {const char * (* getkey) (void ); const void * (* getvalue) (void * arg);/** for the second parameter of the dlopen function * RTLD_NOW: load all functions in the shared library to the memory * RTLD_LAZY: the function loading operation in the shared library is pushed back until a function */void * handle = dlopen (_ STR_PATH, RTLD_LAZY) is loaded when dlsym () is called. // the following error message is displayed, is a careful way to change, each time you check whether the error exists const char * err = dlerror (); If (! Handle | err) {fprintf (stderr, "dlopen" _ STR_PATH "no open! Err = % s \ n ", err); return-1;} getkey = dlsym (handle," getkey "); if (err = dlerror ())) {fprintf (stderr, "getkey err = % s \ n", err); dlclose (handle); return-2;} puts (getkey ()); // This explicitly calls the dll code. Unsafe code injection is too simple. getvalue = dlsym (handle, "getvalue"); if (err = dlerror ())) {fprintf (stderr, "getvalue err = % s \ n", err); dlclose (handle); return-3;} puts (getvalue (NULL )); dlclose (handle); return 0 ;}
Compile code
gcc -g -Wall -o heooso.out heooso.c -ldl
The test results are as follows:
Running everything is normal. The function is implemented, but you must never use it like this. Otherwise, it is quite dangerous. It is also a programming idea.
Note that we will write a backward compatible plug-in mechanism. You can take a look at it for a better understanding of Linux system development.
Linux uses plug-in technology for small projects.
Postscript
Errors are inevitable. Let's talk about how to load plug-ins in linux during dynamic library running. Although it is small, it is very tricky.
Makefile
CC = gcc DEBUG =-g-WallLIB =-ldlRUNSO = $ (CC)-fPIC-shared-o $ ^ RUN = $ (CC) $ (DEBUG) -o $ @ $ ^ # Total task all: libheoo. so libheootwo. so libheoothree. so main. out # simple lib %. so generate libheoo. so: heoo. c $ (RUNSO) libheootwo. so: heootwo. c $ (RUNSO) libheoothree. so: heoothree. c $ (RUNSO) # main content generated. out: main. c $ (RUN) $ (LIB) # A simple clear operation to make clean. PHONY: cleanclean: rm-rf *. so *. s *. I *. o *. out *~ ; Ls-hl
Heoo. h
# Ifndef _ H_HEOO # define _ H_HEOO/** test interface to obtain the key content *: returns the key string */extern const char * getkey (void);/** test interface, get the value content * arg: input parameter *: returned result */extern const void * getvalue (void * arg); # endif //! _ H_HEOO
Heootwo. c
# Include "heoo. h "# include <stdio. h>/** test interface to obtain the key content *: returns the key string */const char * getkey (void) {return "heootwo. c getkey ";}/** test interface to obtain the value content * arg: input parameter *: returned result */const void * getvalue (void * arg) {const char * key = "heootwo. c getvalue "; printf (" % s-% s \ n ", key, (char *) arg); return key ;}
Heoothree. c
# Include "heoo. h "# include <stdio. h>/** test interface to obtain the key content *: returns the key string */const char * getkey (void) {return "heoothree. c getkey ";}/** test interface to obtain the value content * arg: input parameter *: returned result */const void * getvalue (void * arg) {const char * key = "heoothree. c getvalue "; printf (" % s-% s \ n ", key, (char *) arg); return key ;}
Main. c
# Include <stdio. h> # include <stdlib. h> # include <string. h> # include <stdbool. h> # include <errno. h> # include <unistd. h> # include <dirent. h> # include <dlfcn. h> // Number of inserted handles # define _ INT_HND (3) // a maximum of 108 plug-ins are supported # define _ INT_LEN (108) // maximum file path length # define _ INT_BUF (512) // process the dll and save the returned data in a [_ INT_HND, the array length must be bool dll_add (void * a [], const char * dllpath); // process the specified directory and insert the result to, if nowpath is NULL, int dll_new (void * a [] [_ INT_HND ], Int len, const char * nowpath); // release the resource void dll_del (void * a [] [_ INT_HND], int len ); /** Dynamic Loading Mechanism */int main (int argc, char * argv []) {int idx, len, I; void * a [_ INT_LEN] [_ INT_HND]; // The processing result len = dll_new (a, _ INT_LEN, NULL) in the current directory; if (len = 0) {fprintf (stderr, "Thank you for using, no valid plug-in content found! \ N "); exit (1);} // data display puts (" -------------------------------- welcome to use the main plug-in -------------------------------- "); for (I = 0; I <len; ++ I) {const char * (* getkey) (void) = a [I] [1]; printf ("% d => % s \ n", I, getkey ();} printf ("Enter the index to be executed [0, % d) \ n", len); if (scanf ("% d ", & idx )! = 1 | idx <0 | idx> = len) {puts ("fake error command, program exited! "); Goto _ exit;} puts (" execution result: "); const void * (* getvalue) (void * arg) = a [idx] [2]; puts (getvalue (NULL) ;__ exit: puts, and save the returned data in a [_ INT_HND]. The length of this array must be booldll_add (void * a [], const char * dllpath) {const char * (* getkey) (void); const void * (* getvalue) (void * arg); void * handle = dlope N (dllpath, RTLD_LAZY); // the following error message is returned. It is a careful way to check whether the error exists const char * err = dlerror (); if (! Handle | err) return false; getkey = dlsym (handle, "getkey"); if (err = dlerror () {dlclose (handle); return false ;} // This explicitly calls the dll code. Unsafe code injection is too simple. getvalue = dlsym (handle, "getvalue"); if (err = dlerror ())) {dlclose (handle); return false;} // handle, key, value, a [0] = handle; a [1] = getkey; a [2] = getvalue; return true;} // Insert the result of processing the specified directory to a. If nowpath is NULL, intdll_new (void * a [] [_ INT_HND] of the current directory is displayed. int len, Const char * nowpath) {int j = 0, rt; DIR * dir; struct dirent * ptr; char path [_ INT_BUF]; // set the default directory if (! Nowpath |! * Nowpath) nowpath = ". "; // open the directory information if (dir = opendir (nowpath) = NULL) {fprintf (stderr," opendir open % s, error: % s \ n ", nowpath, strerror (errno); exit (-1);} // read the file one by one while (j <len & (ptr = readdir (dir ))) {// only process files, including unknown files if (DT_BLK = ptr-> d_type | DT_UNKNOWN = ptr-> d_type) {rt = snprintf (path, _ INT_BUF, "% s/% s", nowpath, ptr-> d_name); // only true *. so file to run if (rt> 3 & rt <_ INT_BUF & path [RT-1] = 'O' & path [rt-2] ='s '& & path [rt-3] = '. ') {// Add if (dll_add (a [j], path) + + j ;}} closedir (dir); return j;} in data dao array ;} // release the resource voiddll_del (void * a [] [_ INT_HND], int len) {int I =-1; while (++ I <len) dlclose (a [I] [0]);}
Last run
Here, a small demo is complete. For the dynamic library plug-in development on Linux gcc, the analysis is complete. O (runtime _ runtime) O Haha ~