当前位置:网站首页>Dynamic library connection - symbol conflict - global symbol intervention
Dynamic library connection - symbol conflict - global symbol intervention
2022-06-26 10:13:00 【Ruo_ Xiao】
The most important thing is written at the beginning
Symbol conflict during dynamic symbol connection , Another technical term is Global symbolic intervention of shared objects .
The phenomenon that the global symbol of a shared object is covered by the global symbol of another shared object is also called the global symbol of a shared object .
Post the conclusion directly
Global symbols intervene in this problem , actually Linux The dynamic linker under is handled like this :
It defines a rule , That is, when a symbol needs to be added to the global symbol table , If the same symbol name already exists , Then those added later will be ignored ( Ignore the symbol being added ).
chestnuts
1、 Simple point
libA.h
void libA();libA.c
#include <stdio.h>
#include <stdlib.h>
#include "libA.h"
void libA()
{
common();
}
void common()
{
printf("libA common!\n");
}
libB.h
void libB();libB.c
#include <stdio.h>
#include <stdlib.h>
#include "libB.h"
void libB()
{
common();
}
void common()
{
printf("libB common!\n");
}
load_main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
int main()
{
libA();
libB();
return 0;
}
Compile the way 1, First link liba.so Link again libB.so:
gcc -fpic -shared -o liba.so libA.c
gcc -fpic -shared -o libb.so libB.c
gcc load_main.c -o load_test liba.so libb.so -Wl,--rpath=./
perform ./load_test
$libA common!
$libA common!
Compile the way 2, First link libB.so Link again libA.so:
gcc -fpic -shared -o liba.so libA.c
gcc -fpic -shared -o libb.so libB.c
gcc load_main.c -o load_test libb.so liba,so -Wl,--rpath=./
perform ./load_test
$libB common!
$libB common!
The result is a different loading order , The code executed is also different , After loading common Symbols are ignored . So what is printed out is loaded first common Symbol . Dynamic symbolic connection will be in the global The symbol table Search for undefined symbols in , The symbols of the dynamic library will also be added to the global symbol table , When a symbol is to be added to the global symbol table , If the same symbol name already exists , Then ignore the symbol to be added .
2、 Complex point
foo.c
#include <stdio.h>
struct AA {
int a;
int b;
} b = { 3, 3 };
int main();
void foo()
{
b.a = 4;
b.b = 4;
printf("foo:\t(&b)=0x%08x\n\tsizeof(b)=%d\n\tb.a=%d\n\tb.b=%d\n\tmain:0x%08x\n",
&b, sizeof(b), b.a, b.b, main);
}
t2.c
#include <stdio.h>
int b;
int c;
int t2()
{
printf("t2:\t(&b)=0x%08x\n\t(&c)=0x%08x\n\tsizeof(b)=%d\n\tb=%d\n\tc=%d\n",
&b, &c, sizeof(b), b, c);
return 0;
}
main.c
#include <stdio.h>
int b = 1;
int c = 1;
int main()
{
int count = 2;
while (count-- > 0) {
t2();
foo();
printf("main:\t(&b)=0x%08x\n\t(&c)=0x%08x\n\tsizeof(b)=%d\n\tb=%d\n\tc=%d\n",
&b, &c, sizeof(b), b, c);
sleep(1);
}
return 0;
}
Makefile
test: main.o t2.o
gcc -shared -fPIC -o libfoo.so foo.c
gcc -o test main.o t2.o -L. -lfoo -Wl,--rpath=./
main.o: main.c
t2.o: t2.c
.PHONY:clean
clean:
rm -f *.o *.so test*Execution results
t2: (&b)=0x00404040
(&c)=0x00404044
sizeof(b)=4
b=1
c=1
foo: (&b)=0x00404040
sizeof(b)=8
b.a=4
b.b=4
main:0x00401142
main: (&b)=0x00404040
(&c)=0x00404044
sizeof(b)=4
b=4
c=4
t2: (&b)=0x00404040
(&c)=0x00404044
sizeof(b)=4
b=4
c=4
foo: (&b)=0x00404040
sizeof(b)=8
b.a=4
b.b=4
main:0x00401142
main: (&b)=0x00404040
(&c)=0x00404044
sizeof(b)=4
b=4
c=4
Discuss the two issues discussed in the post :
t2.c and main.c Global variables are defined in b,c , However, there is no error of duplicate definition when compiling .$nm main.o
0000000000000000 D b
0000000000000004 D c
U foo
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T main
U printf
U sleep
U t2
$nm t2.o
0000000000000004 C b
0000000000000004 C c
U _GLOBAL_OFFSET_TABLE_
U printf
0000000000000000 T t2
t2.o Medium b and c The type is C,main.o in b and c The type is D.
“C” The symbol is common. Common symbols are uninitialized data. When linking, multiple common symbols may appear with the same name. If the symbol is defined anywhere, the common symbols are treated as undefined references. “D” “d” The symbol is in the initialized data section.
“C” This symbol represents a weak symbol . Weak symbols are uninitialized data . When linking , Multiple weak symbols with the same name may appear . If the strong sign is defined anywhere , The weak symbol is treated as an undefined reference .( Linker behavior , Do not allocate memory space , Relocate when linking relocate To strong sign position )
“D” “d” The symbol is in the initialization data segment .( Strong symbols allocate memory space )
“C” Symbols are interpreted as weak symbols , On strong and weak symbols , Refer to the following sections on strong and weak symbols .
The initialized global variable is strongly signed , Uninitialized global variables are weak symbols , At most one strong symbol can exist , Weak symbols can have many , The linker will eventually choose a strong symbol .
The second question is
stay t2 in b and c The value of is 1, stay foo It becomes 4, look main The variables in seem to be foo covers .
It's not actually main Inside b It is covered. , It is libfoo Inside b Neglected . This phenomenon is also caused by the intervention of symbols .
libfoo.so Symbols in b Also allocated memory , In the data segment .
$nm libfoo.so
0000000000004028 D b
$nm test
0000000000004010 D b Now there are two b Symbol ,main Inside b The symbol has been added to the global symbol table , perform t2() Interface , Also visited main.o Medium b、c Symbol , At this point, the value is 1.
Next, you will call foo(), Loader loading libfoo.so when , Ready to move libfoo.so Symbols in b Import symbols into the global symbol table , But there are already in the global symbol table b Symbol .libfoo.so Medium b The symbol is ignored .foo The interface to access memory is still main.o(test) Medium b and c Memory .
Global symbol intervention is only used to locate symbols , That is, specify which... The symbol belongs to module, Which file , There is no limit to the changes to be made later ( No matter in which module , Which file ). The variables have been analyzed b Documents are used main Symbols in , So the initial value , The address is the value used , When you use it later , Will operate based on this value , So you'll see main / t2 It's still full of 1、1, however foo Then it's all 4,4 了 . In fact, the only thing that global symbol intervention ignores is that you are libfoo.so Internally defined b(3,3).
Strong sign and weak sign
Strong sign : Compiler default functions and initialized global variables
Weak sign : Uninitialized global variables are weak symbols ( It can also be done through gcc Of __attribute__((weak)) Appoint )
Examples of conflicts : If we're in the target file A And target file B All define a global shaping variable g_variable, And initialize them all , In this way, the linker will report when linking multiple definition Error of , This error is because strong symbols cannot be defined more than once .
But if we were here A A is defined in double Type of g_variable,B A int Type of g_variable, None of them has been initialized , Then the linker will select double type 8 bytes g_variable Allocate space .
reason : Because the linker needs to support weak symbol mechanism ( For the program library, this mode is convenient for users to expand and customize ), also The linker does not support the symbol type when linking , Multiple weak symbols are allowed .
If you want to turn off weak symbols, you can use gcc Of “-fno-common” Options
Global symbol defined multiple times , The linker will process according to the following rules :
1. Strong symbols are not allowed to be defined more than once , otherwise , Linker reported duplicate symbol definition error .
2. If a symbol is strong in a target file , In other files are weak symbols , Then choose strong symbols .
3. If a symbol is weak in all target files , Then choose the one that takes up the most space , See the example above .
(SAW:Game Over!)
边栏推荐
- Teach you to use shell script to check whether the server program is running
- What is the web SSH service port of wgcloud
- Get the clicked position in the recyclerview
- P1296 whispers of cows (quick row + binary search)
- 教你用shell脚本检测服务器程序是否在运行
- c语言语法基础之——局部变量及存储类别、全局变量及存储类别、宏定义 学习
- c语言语法基础之——指针( 多维数组、函数、总结 ) 学习
- How to find and install the dependent libraries of Debian system
- Glide's most common instructions
- Redis notes (15) - Pipeline (the client packages and sends batch commands to save network overhead)
猜你喜欢

Force buckle ----- remove the maximum and minimum values from the array

Deep learning (tentsorflow2. version) three good student performance problems (1)

字符串常量池、class常量池和运行时常量池

Win10安装tensorflow-quantum过程详解

Redis novice introduction

DAY 3 数组,前置后置,字符空间,关键词和地址指针

What should the preview do?

What is the web SSH service port of wgcloud

【Leetcode】76. 最小覆盖子串

【LeetCode】59. 螺旋矩阵 II
随机推荐
JVM的符号引用和直接引用是什么
Day 3 array, pre post, character space, keyword and address pointer
Getting started with Flink - word statistics
thymeleaf中抽取公共片段
c语言语法基础之——指针( 多维数组、函数、总结 ) 学习
1. 两数之和(LeetCode题目)
【二分查找】4. 寻找两个正序数组的中位数
存储过程测试入门案例
Poj3682 king arthur's birthday celebration (probability)
Cmake / set command
自动化测试——关于unitest与pytest初始化共存问题
Teach you to use shell script to check whether the server program is running
The first batch of 12 enterprises settled in! Opening of the first time-honored product counter in Guangzhou
What is a botnet
Download MySQL database installation package website of each system and version
The basis of C language grammar -- factoring by function applet
Vscode common programming fonts
Use of exec series functions (EXECL, execlp, execle, execv, execvp)
The basis of C language grammar -- function definition learning
创建对象的时候堆内存的分配