Like window calling library files, under linux , there are also corresponding APIs that exist because of loading library files. They are mainly the following functions:
Function name | Functional description |
---|---|
dlopen | Open the object file so that it can be accessed by the program |
dlsym | dlopen Get the address of the function in the object file that executed the function |
dlerror | This function has no parameters, it will return a string when the previous error occurs, and at the same time it will be saved from memory empty; returns NULL if no error occurs, |
dlclose | Close the target file. If there is no need to call the shared object, the application can call this method to notify The operating system no longer needs handles and object references. It is completely reference counted, so the same Multiple users of a shared object will not conflict with each other (as long as one user is still using it, it will be in memory). Any symbols resolved through a closed object |
Example code (soTest.c):
1 #include <stdio.h> 2 #include <dlfcn.h> 3 4 int main(int argc, char *argv[]){ 5 void * libm_handle = NULL; 6 float (*cosf_method)(float); 7 char *errorInfo; 8 float result; 9 10 // The dlopen function also automatically resolves dependencies in shared libraries. That way, if you open an object that depends on other shared libraries, it will automatically load them. 11 // The function returns a handle, which is used for subsequent API calls 12 libm_handle = dlopen("libm.so", RTLD_LAZY ); 13 // If a NULL handle is returned, it means that the object file cannot be found, and the process ends. Otherwise, a handle of the object will be obtained, and the object can be further inquired 14 if (!libm_handle){ 15 // If the NULL handle is returned, the reason why the object cannot be accessed can be obtained through the dlerror method 16 printf("Open Error:%s. \n",dlerror()); 17 return 0; 18 } 19 20 // Using the dlsym function, try to resolve symbols in the newly opened object file. You will get a valid pointer to the symbol, or get a NULL and return an error 21 cosf_method = dlsym(libm_handle,"cosf"); 22 errorInfo = dlerror();// Call the dlerror method and return an error message At the same time, the error information in the memory is cleared 23 if (errorInfo != NULL){ 24 printf("Dlsym Error:%s.\n",errorInfo); 25 return 0; 26 } 27 28 // Execute "cosf" Method 29 result = (*cosf_method)(0.0); 30 printf("result = %f.\n",result); 31 32 // After calling the target function in the ELF object, close access to it by calling dlclose 33 dlclose(libm_handle); 34 35 return 0; 36 }
In this example, the "cosf" function in the math library (libm.so) is mainly called. The second parameter of the dlopen function indicates the mode of loading the library file. There are two main types: RTLD_LAZY suspends the decision, and waits until necessary Solve symbols; RTLD_NOW resolves immediately, resolves all outstanding symbols before returning. Also remember to quote the header file "#include <dlfcn.h>" (^_^) that contains the API.
Compilation and execution results are as follows:
If the library file name in line 12 of the code is changed to a library file that does not exist, the error result after running is as follows:
If the function name in line 21 of the code is changed to a function name that does not exist, the error result after running is as follows:
This article mainly briefly describes some basic knowledge and points of attention for calling SO library files under linux.
This example passed the test under the 64 system of redhat 5.2.
Personal creation, welcome to point out mistakes.
The ELF format is involved, and the gcc compilation options are to be added. A simple and practical explanation, I have a practical understanding of the so files under Linux.
1. What is the so file?
2. How to generate and use a so dynamic library file?
3. Address space, and thread safety.
4. Initialization and analysis of the library:
5. Replace system functions with functions in our own library:
//------ -------------------------------------------------- -----------------------
1. What is the so file?
It is also an ELF format file, a shared library (dynamic library), similar to a DLL. Save resources, speed up, and simplify code upgrades.
Knowing so much is enough, pragmatism. Wait for the impression to study the principle again.
2. How to generate and use a so dynamic library file?
First write a C file: sc
C code
- #include <stdio.h>
- int count;
- void out_msg(const char *m)
- {//Output 1 message in 2 seconds and count
- for(;;) {printf("%s %d\n", m, ++count); sleep(2);}
- }
Compile: Get the output file libs.o
gcc -fPIC -g -c sc -o libs.o
Link: Get the output file libs.so
gcc -g -shared -Wl,-soname,libs.so -o libs.so libs. o -lc
a header file:sh
C code
- #ifndef _MY_SO_HEADER_
- #define _MY_SO_HEADER_
- void out_msg(const char *m);
- #endif
Another C file to refer to the functions in this library: ts.c
C code
- #include <stdio.h>
- #include "s.h"
- int main(int argc, char** argv)
- {
- printf("TS Main\n");
- out_msg("TS ");
- sleep(5); //This sentence can be commented out, and it can be opened in Section 4.
- printf("TS Quit\n");
- }
Compile and link this file: get the output file ts
gcc -g ts.c -o ts -L. -ls
execute ./ts, um: success. . . I almost
got ts:error while loading shared libraries: libs.so: cannot open shared object file: No such file or directory
The system cannot find the libs.so we defined ourselves, so tell him to modify the variable LD_LIBRARY_PATH, for convenience, write A script: e (the file name is e, too lazy to make it long)
#!/bin/sh
export LD_LIBRARY_PATH=${pwd}:${LD_LIBRARY_PATH}
./ts
execution: ./e &
the screen starts to have The information is output. Of course, you can’t see TS Quit. The front is an infinite loop,
and this sentence will be used later
.
./e&,
what will happen to the screen information at this time? How will the global variable count change?
It will be that the two processes cross-output information, and their respective counts do not interfere with each other, although they refer to the same so file.
That is to say, there is only one statement about whether the code is thread-safe, and there is no statement about whether the code is process-safe.
4. Library initialization and analysis:
Dynamic library loading and unloading under windows will have initialization functions and unloading functions to complete library initialization and resource recovery. Of course, Linux can also implement it.
When the ELF file itself is executed, it will execute a _init() function and a _fini() function to complete this. We only need to let the system execute our own functions at this time.
Modify our previous sc file:
C code
- #include <stdio.h>
- void my_init(void) __attribute__((constructor)); //tell gcc to throw this function into the init section
- void my_fini(void) __attribute__((destructor)); //tell gcc to throw this function into fini section
- void out_msg(const char *m)
- {
- printf(" Ok!\n");
- }
- int i; //still a counter
- void my_init(void)
- {
- printf("Init ... ... %d\n", ++i);
- }
- void my_fini(void)
- {
- printf("Fini ... ... %d\n", ++i);
- }
There is no need to recompile libs.so and ts, which is much more convenient for code maintenance and upgrading.
Then execute: ./e &
you can see the screen output: (incomplete information, just the same order)
Init
Main
OK
Quit
Fini
can see that the initialization function and analysis function we defined have been executed, and it is at the front and Last.
If the sleep(5) in sc is not commented out, then there is a chance:
./e&
./e& is executed twice in a row, then the initialization function and analysis function will also be executed twice, although the system only loads libs.so once.
If the background process is killed during sleep, the parsing function will not be executed.
5. Use the functions in our own library to replace the system functions:
create a new file bc: we want to replace the system functions malloc and free (you can write a memory leak detection tool yourself)
C code
- #include <stdio.h>
- void* malloc(int size)
- {
- printf("My malloc\n");
- return NULL;
- }
- void free(void* ad)
- {
- printf("My free\n");
- }
The old rule, compile and link into a so file: get libb.so
gcc -fPIC -g -c bc -o libb.o
gcc -g -shared -Wl,-soname,libb.so -o libb.so -lc
modify sc : Regenerate libs.so
C code
- void out_msg()
- {
- int *p;
- p = (int*)malloc(100);
- free(p);
- printf("Stop Ok!\n");
- }
Modify the script file e:
#!/bin/sh
export LD_PRELOAD=${pwd}libb.so:${LD_PRELOAD}
export LD_LIBRARY_PATH=${pwd}:${LD_LIBRARY_PATH}
./ts
The key is on LD_PRELOAD, this path The specified so will be loaded before all so, and the symbols will override the symbols in the so files loaded later. This variable is ignored if the permissions of the executable are not appropriate (SID).
Execution: ./e &
Well, we can see that our malloc and free are working.
That's all I can think of for now.