Function calls in dynamic libraries
Environment:
- Clang version 12.0.1
- Cmake version 3.21.2
- G + + 11.1.0 (GCC)
A library link conflict containing two identical functions
Imagine calling a function in your main function, but that function can be implemented in different libraries. Which function should be called in your main function?
Let’s experiment and build the test code:
. ├ ─ ─ CMakeLists. TXT ├ ─ ─ the include │ ├ ─ ─ second. H │ └ ─ ─ work. H ├ ─ ─ main. Cc └ ─ ─ the SRC ├ ─ ─ CMakeLists. TXT ├ ─ ─ second. Cc └ ─ ─ work.ccCopy the code
./ cmakelists. TXT File contents:
Cmake_minimum_required (VERSION 3.14) Project (symbol) include_directories(include) add_subdirectory(SRC) add_executable(${PROJECT_NAME} main.cc) target_link_libraries(${PROJECT_NAME} second work)Copy the code
./include/second.h
#pragma once
#include <iostream>
void SoFunction(a);
void DoFunction(a);
Copy the code
./include/work.h
#pragma once
#include <iostream>
void SoFunction();
Copy the code
SRC/CMakeLists. TXT content:
include_directories(${CMAKE_PROJECT_PATH}/include)
add_library(second SHARED second.cc)
add_library(work SHARED work.cc)
Copy the code
src/second.cc
#include "second.h"
void SoFunction(a)
{
std::cout << "conflict function call\n";
}
void DoFunction(a)
{
std::cout<<"DoFunction\n";
SoFunction(a); }Copy the code
src/work.cc
#include "work.h"
void SoFunction(a) { std::cout << "Call Sofunctiuon\n"; }
Copy the code
./main.cc
#include <iostream>
void SoFunction(a);
int main(a) {
std::cout<<"1. Main start... \n";
SoFunction(a); std::cout<<"SoFunction call finished\n";
return 0;
}
Copy the code
Build run :mkdir build && pushd build && cmake.. && make &&./symbol && popd && rm -rf build
conflict function call
SoFunction call finished
Copy the code
Cc/cmakelists.txt/cmakelists.txt/cmakelists.txt/cmakelists.txt/cmakelists.txt/cmakelists.txt/cmakelists.txt/cmakelists.txt/cmakelists.txt/cmakelists.txt/cmakelists.txt/cmakelists.txt/cmakelists.txt Different results.
Dynamic library call override problem containing two identical functions
If we call second/DoFunction in the main function and it calls SoFunction, will we call SoFunction in second. Cc or SoFunction in work.cc? Modify the main function to test:
#include <iostream>
#include "second.h"
#include "work.h"
int main(a) {
std::cout<<"1. Main start... \n";
DoFunction(a); std::cout<<"DoFunction call finished\n";
SoFunction(a);return 0;
}
Copy the code
We do not change the link order, keep second first link, we get the following result:
1. Main start...
Second DoFunction
conflict function call
DoFunction call finished
conflict function call
Copy the code
Not surprisingly, the order of function calls is:main.cc/DoFunction->second.cc/DoFunction->second.cc/SoFunction->work.cc/SoFunction
Now let’s modify./CMakeLists.txt
To adjust the link ordertarget_link_libraries(${PROJECT_NAME} work second)
Rerun the code, we should get the following result:
1. Main start...
Second DoFunction
Call Sofunctiuon
DoFunction call finished
Call Sofunctiuon
Copy the code
Functions are called in the following order:main.cc/DoFunction->second.cc/DoFunction->work.cc/SoFunction->work.cc/SoFunction
Because of the delta functionSoFunction
becauselibwork.so
First link, the function uses its. How can functions in the same library still call each other when the link order changes?
Nm-cd SRC /libwork.so
U __cxa_atexit@GLIBC_2.2.5 w __cxa_finalize@GLIBC_2.2.5 w __gmon_start__ W _ITM_deregisterTMCloneTable W _ITM_registerTMCloneTable 0000000000001129 T SoFunction() U STD :: iOS_BASE ::Init::Init() @glibcXX_3.4U STD :: iOS_BASE ::Init::~Init() @glibcxx_3.4u STD ::cout@GLIBCXX_3.4 U STD ::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, STD :: Char_traits < har> >&, char const*) @glibcxx_3.4Copy the code
Libsecond-so contains the following contents:
U __cxa_atexit@GLIBC_2.2.5 w __cxa_finalize@GLIBC_2.2.5 w __gmon_start__ W _ITM_deregisterTMCloneTable W _ITM_registerTMCloneTable 0000000000001159 T DoFunction() 0000000000001139 T SoFunction() U STD :: iOS_BASE ::Init::Init() @glibcxx_3.4U STD :: iOS_Base ::Init::Init() @glibcxx_3.4U STD :: iOS_BASE ::Init::~Init() @glibcxx_3.4U STD ::cout@GLIBCXX_3.4 U std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, STD :: Char_traits < har> >&, char const*) @glibcxx_3.4Copy the code
Resolve incorrect calls caused by symbol conflicts
Hidden symbols
“Unavailable” dynamic library symbols can be set to unavailable, for example, libwork.so symbols can be unavailable, so that second is available anyway. You can set SRC/cmakelists.txt to the following:
include_directories(${CMAKE_PROJECT_PATH}/include)
if(UNIX AND CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
add_library(work SHARED work.cc)
endif(a)add_library(second SHARED second.cc)
Copy the code
The compilation process above will automatically hide two library symbols (CXX_FLAG in current CMakeLists. TXT has been effective, cannot be directly set a parameter, a plus), at that time we see libwork. So symbol information, perform when run the compiler will go wrong, because I couldn’t find the symbol table DoF Unction and SoFunction, resulting in undefined references.
U __cxa_atexit@GLIBC_2.2.5 w __cxa_finalize@GLIBC_2.2.5 w __gmon_start__ W _ITM_deregisterTMCloneTable W _ITM_registerTMCloneTable U STD :: iOS_BASE ::Init::Init() @glibcxx_3.4U STD :: iOS_BASE ::Init::Init() @glibcxx_3.4U STD: : cout@GLIBCXX_3.4 U STD: : basic_ostream < char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, Char const *) @ GLIBCXX_3. 4Copy the code
Here we use manual link to generate the final binary :clang++ main.cc -iinclude-l. -lsecond -lwork -o symbol This will mask libwork.so to only call SoFunction in second.cc. The results are as follows:
1. Main start...
Second DoFunction
conflict function call
SoFunction call finished
conflict function call
Copy the code
Disable in function code
Cc: libsecond. Cc: libsecond. Soclang++ -fvisibility=hidden libsecond -Iinclude src/second.cc -fPIC -shared -o libsecond.so)
#include "second.h"
__attribute__ ((visibility ("default"))) void SoFunction()
{
std::cout << "conflict function call\n";
}
__attribute__ ((visibility ("default"))) void DoFunction()
{
std::cout<<"Second DoFunction\n";
SoFunction();
}
Copy the code
Then open the visibility in SRC/cmakelists. TXT, and the compilation will run normally, because the symbols in work.cc are not exposed, so we will not change the SoFunction in work.cc.
Export function tables through file Settings
Add the following information to the include/export.symb file:
{
global: *SoFunction*;
local: *;
};
Copy the code
- Global: corresponds to the function you want to export
- The local area represents symbols that you do not want to export, and the asterisk (*) indicates that all symbols except those in global are not exported
Manual compilation of the dynamic library implementation only preserves SoFunctionclang++ -wl,–version-script=include/ export-symb-s-iinclude SRC/second-.cc-fpic-shared-o Libsecond. So libsecond.
U __cxa_atexit@GLIBC_2.2.5 w __cxa_finalize@GLIBC_2.2.5 w __gmon_start__ W _ITM_deregisterTMCloneTable W _ITM_registerTMCloneTable 0000000000001190 T DoFunction() U STD :: iOS_BASE ::Init::Init() @glibcXX_3.4U STD :: iOS_BASE ::Init::~Init() @glibcxx_3.4u STD ::cout@GLIBCXX_3.4 U STD ::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, STD :: Char_traits < har> >&, char const*) @glibcxx_3.4Copy the code
The output is as follows:
1. Main start...
Second DoFunction
conflict function call
DoFunction call finished
Call Sofunctiuon
Copy the code
The output here is a bit different (we’ve masked SoFunction in second.cc)
reference
How to resolve symbol conflicts when compiling links