为什么与静态库链接的共享库表现得像与动态库链接一样?

Why shared library linked with static library behaves like it was linked with dynamic one?

我不清楚为什么最终共享 .so 库调用静态 .a 库中的函数为:

callq  1050 <add@plt>

我希望看到类似的内容:

callq  115b <add>

让我举例说明。

假设我们有以下文件。

int add(int a, int b)
{
    return a+b;
}
extern int add(int a, int b);

int use_add_from_shared_library_1(int a, int b)
{
    return add(a, b);
}

int main() { return 0; }

让我们编译静态库(为了方便):

CC=gcc;
${CC} -c -fPIC static_library.c -o static_library.o;
ar rcs libstatic_library.a static_library.o;

现在让我们编译共享库并link到它之前编译的静态库:

CC=gcc;
${CC} -c -fPIC shared_library.c -o shared_library.o;
${CC} -shared shared_library.o -L./ -lstatic_library -o shared_library.so;

不会有错误。 但是,共享库的“objdump”将包含反汇编代码:

$ objdump -dS shared_library.so | grep "callq" | grep "add";
    1135:   e8 16 ff ff ff          callq  1050 <add@plt>

P.S。单-shell例子:

echo '
int add(int a, int b)
{
    return a+b;
}
' \
  > static_library.c; \
\
echo '
extern int add(int a, int b);

int use_add_from_shared_library_1(int a, int b)
{
    return add(a, b);
}

int main() { return 0; }
' \
  > shared_library.c; \
\
CC=gcc; \
\
${CC} -c -fPIC static_library.c -o static_library.o; \
ar rcs libstatic_library.a static_library.o; \
\
${CC} -c -fPIC shared_library.c -o shared_library.o; \
${CC} -shared shared_library.o -L./ -lstatic_library -o shared_library.so; \
\
objdump -dS shared_library.so | grep "callq" | grep "add";

共享库和静态库是截然不同的东西。

静态库字面意思是一个归档文件,类似于.tar文件,其内容是目标文件。通常,这些文件会增加目标文件中定义的外部符号的索引。在静态 linking 期间,linker 从库中提取部分或全部目标文件,并 links 那些与任何其他指定对象的目标文件,就好像提取的目标文件有直接指定了基于提供它们的对象或该对象是否来自(静态)库,外部符号之间没有固有的区别。

共享库是集成对象,非常类似于程序。它们可以成为可执行程序。其中没有单独的目标文件。在具有 position-independent 代码的 shared-library 格式中,库提供的所有外部符号必须是 position-independent.

当您 link 将静态库转换为共享库时,您是在要求 linker 在生成的共享库中包含静态库中部分或全部目标文件的内容图书馆。这是它唯一可行的方法。从静态库解析的外部符号也将是共享库中的外部符号,因此对它们的引用需要是相对的,包括来自共享库中的其他函数。