use*_*462 3 c++ g++ dynamic-linking
我可能对动态链接的工作方式感到误解,因为我无法弄清楚。据我了解,动态链接库时,其符号在运行时解析。从这个答案:
当您动态链接时,可执行文件中将包含指向要链接的文件的指针(例如,文件的文件名),并且链接时不包含该文件的内容。只有当您以后运行该可执行文件时,这些动态链接的文件才被购买,并且它们仅被购买到该可执行文件的内存中副本中,而不是磁盘中的一个副本中。
[...]
在动态情况下,主程序与C运行时导入库(声明动态库中的内容但未实际定义的内容)链接在一起。即使实际的代码丢失,这也允许链接器链接。
然后,在运行时,操作系统加载程序将主程序与C运行时DLL(动态链接库或共享库或其他命名法)进行后期链接。
我对为什么g++
动态链接到共享对象时似乎期望共享对象在那里感到困惑。当然,我希望库的名称是必需的,以便可以在运行时加载它,但是为什么.so
在此阶段它是必需的?此外,g++
在链接库时,抱怨未定义的引用。
我的问题是:
g++
如果库的加载仅在运行时发生,为什么在动态链接共享对象时似乎需要共享对象?我知道-l
指定共享对象的名称可能需要该标志,以便可以在运行时加载它,但是我看不出必须提供.so
指向链接时间(-L
)或.so
自身的路径。g++
在动态链接时尝试解析符号?没有什么可以阻止我.so
在链接时完成操作,而是.so
在运行时提供一个不同的(不完整的)消息,这会导致程序在尝试使用未定义的符号时崩溃。我举了一个可重现的例子:
.
??? main.cpp
??? test
??? usertest.cpp
??? usertest.h
Run Code Online (Sandbox Code Playgroud)
#ifndef USERTEST_H_4AD3C656_8109_11E8_BED5_5BE6E678B346
#define USERTEST_H_4AD3C656_8109_11E8_BED5_5BE6E678B346
namespace usertest
{
void helloWorld();
// This method is not defined anywhere
void byeWorld();
};
#endif /* USERTEST_H_4AD3C656_8109_11E8_BED5_5BE6E678B346 */
Run Code Online (Sandbox Code Playgroud)
#include "usertest.h"
#include <iostream>
void usertest::helloWorld()
{
std::cout << "Hello, world\n";
}
Run Code Online (Sandbox Code Playgroud)
#include "test/usertest.h"
int main()
{
usertest::helloWorld();
usertest::byeWorld();
}
Run Code Online (Sandbox Code Playgroud)
$ cd test
$ g++ -c -fPIC usertest.cpp
$ g++ usertest.o -shared -o libusertest.so
$ cd ..
$ g++ main.cpp -L test/ -lusertest
$ LD_LIBRARY_PATH="test" ./a.out
Run Code Online (Sandbox Code Playgroud)
我希望所有尝试启动时都崩溃,a.out
因为它无法在中找到必要的符号libusertest.so
。
建立a.out
链接时失败,因为它找不到byeWorld()
:
/tmp/ccVNcRRY.o: In function `main':
main.cpp:(.text+0xa): undefined reference to `usertest::byeWorld()'
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
使用ELF格式,实际上不必知道哪个符号属于哪个库,因为在执行程序时会发生实际的符号解析。尽管按照惯例ld
,在生成二进制文件时仍会解析符号。这是为了您的方便,以便在缺少符号时立即获得反馈,因为在这种情况下,您的程序将无法运行。
使用该--warn-unresolved-symbols
标志,可以将ld
这种情况下的行为从错误更改为警告:
$ g++ -Wl,--warn-unresolved-symbols main.cpp -lusertest
Run Code Online (Sandbox Code Playgroud)
应该发出警告,但仍创建可执行文件。请注意,您仍然需要提供库名称,否则ld
将不知道在哪里寻找所需的符号。
在Windows上,链接器需要确切知道哪个符号属于哪个库,才能生成必要的导入表。因此,不可能用未解析的符号构建PE二进制文件。
归档时间: |
|
查看次数: |
335 次 |
最近记录: |