我使用say(abc.so
,a.c
,b.c
)文件共享库文件c.c
。
现在我通过可执行文件说target.out
我怀疑是......我可以删除abc.so
并再次从(abc.so
,a.c
,b.c
再次构建c.c
并将其粘贴到任何地方我以前的abc.so
出席了。
但是我的target.out
是较旧的。
现在,如果我运行target.out
,它将适用于新的abc.so
??
答案 0 :(得分:0)
是的,它会起作用,但你必须小心。
我们以libtest.c为例:
int my_global_var = 42;
int sum(int a, int b)
{
return a + b;
}
它可以用:
构建gcc -fPIC -shared -o libtest.so libtest.c
使用readelf -s libtest.so
,我们可以看到函数和全局变量作为公共符号公开:
$ readelf -s libtest.so
42: 0000000000200950 4 OBJECT GLOBAL DEFAULT 21 my_global_var
...
47: 0000000000000665 42 FUNC GLOBAL DEFAULT 11 sum
...
重要的是要注意.so
文件没有指定这些符号的类型或原型。
现在让我们编写一个使用lib的程序:
#include <stdio.h>
/* provided by libtest */
int sum(int, int);
extern int my_global_var;
int main()
{
printf("5 + 2 = %d and my_global_var = %d\n", sum(5, 2), my_global_var);
return 0;
}
建立它:
gcc -L. -ltest -o program program.c
有效:
$ ./program
5 + 2 = 7 and my_global_var = 42
我们可以看到program
动态链接到libtest.so
:
$ ldd program
...
libtest.so (0x00007f1138c70000)
...
在没有类型或原型的程序头中再次引用符号sum
和my_global_var
:
$ objdump --dynamic-reloc program
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
0000000000600b00 R_X86_64_GLOB_DAT __gmon_start__
0000000000600b50 R_X86_64_COPY my_global_var
0000000000600b20 R_X86_64_JUMP_SLOT printf
0000000000600b28 R_X86_64_JUMP_SLOT __libc_start_main
0000000000600b30 R_X86_64_JUMP_SLOT __gmon_start__
0000000000600b38 R_X86_64_JUMP_SLOT sum
这就是它的工作原理,只要库文件存在并且它包含程序引用的符号,动态链接器就会很高兴并将这些符号的地址写入程序内存中的特殊间接表。
如果我们将my_global_var
更改为43,请重建lib,然后运行该程序而不重建它:
$ ./program
5 + 2 = 7 and my_global_var = 43
如果我们从lib中删除my_global_var
,符号就会消失,程序无法启动,因为动态链接器不满意:
$ ./program
./program: symbol lookup error: ./program: undefined symbol: my_global_var
现在是棘手的部分,让我们尝试更改sum
的原型:
int my_global_var = 43;
float sum(float a, float b)
{
return a + b;
}
我们重建了库,并运行程序:
$ ./program
5 + 2 = 791621423 and my_global_var = 43
动态链接器不会抱怨,但是当程序将int
传递给期望float
s的函数时,结果就是垃圾。
总结一下:只要类型和原型保持绝对不变,它就会起作用。如果它们发生变化,链接器就不会抱怨并且会发生奇怪的事情。
要解决最后一个问题,大型库使用符号版本控制。这是一个非常复杂的主题,这里有一篇关于它的详细文章:http://www.trevorpounds.com/blog/?p=33